home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_xemacs.idb / usr / freeware / lib / xemacs-20.4 / lisp / w3 / w3-parse.el.z / w3-parse.el
Encoding:
Text File  |  1998-05-21  |  119.9 KB  |  2,812 lines

  1. ;; Created by: Joe Wells, jbw@cs.bu.edu
  2. ;; Created on: Sat Sep 30 17:25:40 1995
  3. ;; Filename: w3-parse.el
  4. ;; Purpose: Parse HTML and/or SGML for Emacs W3 browser.
  5.  
  6. ;; Copyright ⌐ 1995, 1996, 1997  Joseph Brian Wells
  7. ;; Copyright ⌐ 1993, 1994, 1995 by William M. Perry <wmperry@cs.indiana.edu>
  8. ;; 
  9. ;; This program is free software; you can redistribute it and/or modify
  10. ;; it under the terms of the GNU General Public License as published by
  11. ;; the Free Software Foundation; either version 2 of the License, or
  12. ;; (at your option) any later version.
  13. ;; 
  14. ;; This program is distributed in the hope that it will be useful,
  15. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. ;; GNU General Public License for more details.
  18. ;; 
  19. ;; You should have received a copy of the GNU General Public License
  20. ;; along with GNU Emacs; see the file COPYING.  If not, write to the
  21. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  22. ;; Boston, MA 02111-1307, USA.
  23. ;;
  24. ;; On November 13, 1995, the license was available at
  25. ;; <URL:ftp://prep.ai.mit.edu/pub/gnu/COPYING-2.0>.  It may still be
  26. ;; obtainable via that URL.
  27.  
  28.  
  29. ;;;
  30. ;;; Trying to make the best of an evil speed hack.
  31. ;;;
  32.  
  33. ;; Explanation:
  34.  
  35. ;; Basically, this file provides one big function (w3-parse-buffer) and
  36. ;; some data structures.  However, to avoid code redundancy, I have broken
  37. ;; out some common subexpressions of w3-parse-buffer into separate
  38. ;; functions.  I have declared these separate functions with "defsubst" so
  39. ;; they will be inlined into w3-parse-buffer.  Also, I have defined them
  40. ;; within eval-when-compile forms, so no definitions will be emitted into
  41. ;; the .elc file for these separate functions.  (They will work normally
  42. ;; when the uncompiled file is loaded.)
  43.  
  44. ;; Each of these subfunctions use some scratch variables in a purely local
  45. ;; fashion.  In good software design, I would declare these variables as
  46. ;; close to their use as possible with "let".  However, "let"-binding
  47. ;; variables is *SLOW* in Emacs Lisp, even when compiled.  Since each of
  48. ;; these functions is executed one or more time during each iteration of
  49. ;; the main loop, I deemed this too expensive.  So the main function does
  50. ;; the "let"-binding of these variables.  However, I still want to declare
  51. ;; them close to their use, partially to keep the compiler from crying
  52. ;; "Wolf!" when there is no danger (well, maybe a little danger :-), so I
  53. ;; define some macros for this purpose.
  54.  
  55. ;; Also, there are some variables which are updated throughout the file
  56. ;; (remember this is really all one function).  Some of the code which
  57. ;; updates them is located inside the subfunctions.  So that the compiler
  58. ;; will not complain, these variables are defined with defvar.
  59.  
  60. (require 'w3-vars)
  61. (require 'mule-sysdp)
  62.  
  63. (eval-when-compile
  64.   (defconst w3-p-s-var-list nil
  65.     "A list of the scratch variables used by functions called by
  66. w3-parse-buffer which it is w3-parse-buffer's responsibility to
  67. \"let\"-bind.")
  68.  
  69.   (defmacro w3-p-s-var-def (var)
  70.     "Declare VAR as a scratch variable which w3-parse-buffer must
  71. \"let\"-bind."
  72.     (` (eval-when-compile
  73.          (defvar (, var))
  74.          (or (memq '(, var) w3-p-s-var-list)
  75.              (setq w3-p-s-var-list (cons '(, var) w3-p-s-var-list))))))
  76.  
  77.   (defmacro w3-p-s-let-bindings (&rest body)
  78.     "\"let\"-bind all of the variables in w3-p-s-var-list in BODY."
  79.     (` (let (, w3-p-s-var-list)
  80.          (,@ body))))
  81.   (put 'w3-p-s-let-bindings 'lisp-indent-function 0)
  82.   (put 'w3-p-s-let-bindings 'edebug-form-spec t)
  83.  
  84.   (defvar w3-p-d-current-element)
  85.   (put 'w3-p-d-current-element 'variable-documentation
  86.        "Information structure for the current open element.")
  87.   
  88.   (defvar w3-p-d-exceptions)
  89.   (put 'w3-p-d-exceptions 'variable-documentation
  90.        "Alist specifying elements (dis)allowed because of an (ex|in)clusion
  91. exception of some containing element (not necessarily the immediately
  92. containing element).  Each item specifies a transition for an element
  93. which overrides that specified by the current element's content model.
  94. Each item is of the form (TAG ACTION *same ERRORP).")
  95.   
  96.   (defvar w3-p-d-in-parsed-marked-section)
  97.   (put 'w3-p-d-in-parsed-marked-section 'variable-documentation
  98.        "Are we in a parsed marked section so that we have to scan for \"]]>\"?")
  99.  
  100.   (defvar w3-p-d-non-markup-chars)
  101.   (put 'w3-p-d-non-markup-chars 'variable-documentation
  102.        "The characters that do not indicate the start of markup, in the format
  103. for an argument to skip-chars-forward.")
  104.  
  105.   (defvar w3-p-d-null-end-tag-enabled)
  106.   (put 'w3-p-d-null-end-tag-enabled 'variable-documentation
  107.        "Is the null end tag (\"/\") enabled?")
  108.  
  109.   (defvar w3-p-d-open-element-stack)
  110.   (put 'w3-p-d-open-element-stack 'variable-documentation
  111.        "A stack of the currently open elements, with the innermost enclosing
  112. element on top and the outermost on bottom.")
  113.  
  114.   (defvar w3-p-d-shortrefs)
  115.   (put 'w3-p-d-shortrefs 'variable-documentation
  116.        "An alist of the magic entity reference strings in the current
  117. between-tags region and their replacements.  Each item is of the format
  118. \(REGEXP . REPLACEMENT-STRING\).  Although in SGML shortrefs normally name
  119. entities whose value should be used as the replacement, we have
  120. preexpanded the entities for speed.  We have also regexp-quoted the
  121. strings to be replaced, so they can be used with looking-at.  This should
  122. never be in an element's overrides field unless
  123. w3-p-d-shortref-chars is also in the field.")
  124.   
  125.   (defvar w3-p-d-shortref-chars)
  126.   (put 'w3-p-d-shortref-chars 'variable-documentation
  127.        "A string of the characters which can start shortrefs in the current
  128. between-tags region.  This must be in a form which can be passed to
  129. skip-chars-forward and must contain exactly the characters which start the
  130. entries in w3-p-d-shortrefs.  If this variable is mentioned in the
  131. overrides field of an element, its handling is magical in that the
  132. variable w3-p-d-non-markup-chars is saved to the element's undo-list and
  133. updated at the same time.  This should never be in an element's overrides
  134. field unless w3-p-d-shortrefs is also in the field.")
  135.   
  136.   (defvar w3-p-d-tag-name)
  137.   (put 'w3-p-d-tag-name 'variable-documentation
  138.        "Name of tag we are looking at, as an Emacs Lisp symbol.
  139. Only non-nil when we are looking at a tag.")
  140.  
  141.   (defvar w3-p-d-end-tag-p)
  142.   (put 'w3-p-d-end-tag-p 'variable-documentation
  143.        "Is the tag we are looking at an end tag?
  144. Only non-nil when we are looking at a tag.")
  145.   
  146.   )
  147.  
  148.  
  149. ;;;
  150. ;;; HTML syntax error messages.
  151. ;;;
  152.  
  153. (eval-when-compile
  154.  
  155.   (defvar w3-p-d-debug-url)
  156.   (put 'w3-p-d-debug-url 'variable-documentation
  157.        "Whether to print the URL being parsed before an error messages.
  158. Only true for the first error message.")
  159.  
  160.   ;; The level parameter indicates whether the error is (1) very
  161.   ;; serious, must be displayed to all users, (2) invalid HTML, but the
  162.   ;; user should only be told if the user has indicated interest, or (3)
  163.   ;; valid HTML which is bad because it appears to rely on the way certain
  164.   ;; browsers will display it, which should only be displayed to the user
  165.   ;; if they have really asked for it.
  166.   
  167.   (defmacro w3-debug-html (&rest body)
  168.     "Emit a warning message.
  169. These keywords may be used at the beginning of the arguments:
  170.   :mandatory-if sexp -- force printing if sexp evaluates non-nil.
  171.   :bad-style         -- do not print unless w3-debug-html is 'style.
  172.   :outer             -- do not include the current element in the element
  173.                         context we report. 
  174.   :nocontext         -- do not include context where error detected.
  175. The remaining parameters are treated as the body of a progn, the value of
  176. which must be a string to use as the error message."
  177.     (let (mandatory-if bad-style outer nocontext condition)
  178.       (while (memq (car body) '(:mandatory-if :bad-style :outer :nocontext))
  179.         (cond ((eq ':mandatory-if (car body))
  180.                (setq mandatory-if (car (cdr body)))
  181.                (setq body (cdr (cdr body))))
  182.               ((eq ':bad-style (car body))
  183.                (setq bad-style t)
  184.                (setq body (cdr body)))
  185.               ((eq ':nocontext (car body))
  186.                (setq nocontext t)
  187.                (setq body (cdr body)))
  188.               ((eq ':outer (car body))
  189.                (setq outer t)
  190.                (setq body (cdr body)))))
  191.       (setq condition (if bad-style
  192.                           '(eq 'style w3-debug-html)
  193.                         'w3-debug-html))
  194.       (if mandatory-if
  195.           (setq condition
  196.                 (` (or (, mandatory-if)
  197.                        (, condition)))))
  198.       (` (if (, condition)
  199.              (let ((message (progn (,@ body))))
  200.                (if message
  201.                    (w3-debug-html-aux message
  202.                                       (,@ (if nocontext
  203.                                               (list outer nocontext)
  204.                                             (if outer '(t)))))))))))
  205.  
  206.   ;; This is unsatisfactory.
  207.   (put 'w3-debug-html 'lisp-indent-function 0)
  208.   
  209.   (put 'w3-debug-html 'edebug-form-spec
  210.        '([&rest &or ":nocontext" ":outer" [":mandatory-if" form] ":bad-style"]
  211.          &rest form))
  212.   )
  213.  
  214. (defun w3-debug-html-aux (message &optional outer nocontext)
  215.   (push (if nocontext
  216.             message
  217.           (concat message
  218.                   ;; Display context information for each error
  219.                   ;; message.
  220.                   "\n  Containing elements: "
  221.                   (w3-open-elements-string (if outer 1))
  222.                   (concat
  223.                    "\n  Text around error: "
  224.                    (save-restriction
  225.                      (widen)
  226.                      (progn
  227.                        (insert "*ERROR*")
  228.                        (prog1
  229.                            (w3-quote-for-string
  230.                             (buffer-substring 
  231.                              (max (- (point) 27) (point-min))
  232.                              (min (+ (point) 20) (point-max))))
  233.                          (delete-char -7))))))) w3-current-badhtml))
  234.  
  235. (defun w3-quote-for-string (string)
  236.   (save-excursion
  237.     (set-buffer (get-buffer-create " w3-quote-whitespace"))
  238.     (erase-buffer)
  239.     (insert string)
  240.     (goto-char (point-min))
  241.     (insert "\"")
  242.     (while (progn
  243.              (skip-chars-forward "^\"\\\t\n\r")
  244.              (not (eobp)))
  245.       (insert "\\" (cdr (assq (char-after (point)) '((?\" . "\"")
  246.                                                      (?\\ . "\\")
  247.                                                      (?\t . "t")
  248.                                                      (?\n . "n")
  249.                                                      (?\r . "r")))))
  250.       (delete-char 1))
  251.     (insert "\"")
  252.     (buffer-string)))
  253.  
  254.  
  255. ;;;
  256. ;;; General entity references and numeric character references.
  257. ;;;
  258.  
  259. ;; *** MULE conversion?
  260. ;; *** I18N HTML support?
  261.  
  262. (let ((html-entities w3-html-entities))
  263.   (while html-entities
  264.     (put (car (car html-entities)) 'html-entity-expansion
  265.      (cons 'CDATA (if (integerp (cdr (car html-entities)))
  266.                           (char-to-string
  267.                            (mule-make-iso-character (cdr (car html-entities))))
  268.             (cdr (car html-entities)))))
  269.     (setq html-entities (cdr html-entities))))
  270.  
  271. ;; These are handled differently than the normal HTML entities because
  272. ;; we need to define the entities with 'nil instead of 'CDATA so
  273. ;; that they are correctly scanned for new markup.
  274. ;;
  275. ;; from jbw@cs.bu.edu
  276. ;;
  277. ;;> Of course, this differs from the specification a bit.  The W3C tech
  278. ;;> report defines all of these as SYSTEM entities.  This potentially means
  279. ;;> that they can be used in more contexts.  The method I outlined above
  280. ;;> means "&smiley;" can only be used in contexts where IMG is a valid
  281. ;;> element.  I am not sure exactly where it is okay to use a SYSTEM entity.
  282. ;;> I think anywhere that data characters are accepted.
  283. ;;
  284. ;; I find this acceptable, as just what the hell are you supposed to do with
  285. ;; &computer; as part of a value of a form input when you display it and/or
  286. ;; submit it?!
  287.  
  288. (let ((html-entities w3-graphic-entities)
  289.       (cur nil))
  290.   (while html-entities
  291.     (setq cur (car html-entities)
  292.           html-entities (cdr html-entities))
  293.     (put (nth 0 cur) 'html-entity-expansion
  294.      (cons 'nil (format "<img src=\"%s/%s%s\" alt=\"%s\">"
  295.                             w3-icon-directory
  296.                             (nth 1 cur)
  297.                             (if w3-icon-format
  298.                                 (concat "." (symbol-name w3-icon-format))
  299.                               "")
  300.                             (or (nth 3 cur) (nth 2 cur)))))))
  301.  
  302. ;; These are the general entities in HTML 3.0 in terms of which the math
  303. ;; shortrefs are defined:
  304. ;; 
  305. ;;   <!ENTITY REF1   STARTTAG   "SUP">
  306. ;;   <!ENTITY REF2   ENDTAG     "SUP">
  307. ;;   <!ENTITY REF3   STARTTAG   "SUB">
  308. ;;   <!ENTITY REF4   ENDTAG     "SUB">
  309. ;;   <!ENTITY REF5   STARTTAG   "BOX">
  310. ;;   <!ENTITY REF6   ENDTAG     "BOX">
  311. ;; 
  312. ;; We're ignoring them because these names should really be local to the
  313. ;; DTD and not visible in the document.  They might change at any time in
  314. ;; future HTML standards.
  315.  
  316. ;; <!--Entities for language-dependent presentation (BIDI and contextual analysis) -->
  317. ;; <!ENTITY zwnj CDATA "‌"-- zero width non-joiner-->
  318. ;; <!ENTITY zwj  CDATA "‍"-- zero width joiner-->
  319. ;; <!ENTITY lrm  CDATA "‎"-- left-to-right mark-->
  320. ;; <!ENTITY rlm  CDATA "‏"-- right-to-left mark-->
  321.  
  322. ;; Entity names are case sensitive!
  323.  
  324. ;; & should only be recognized when followed by letter or # and
  325. ;; digit or # and letter.
  326.  
  327. (eval-when-compile
  328.  
  329.   (w3-p-s-var-def w3-p-s-entity)
  330.   (w3-p-s-var-def w3-p-s-pos)
  331.   (w3-p-s-var-def w3-p-s-num)
  332.   ;; Destroys free variables:
  333.   ;;   w3-p-s-entity, w3-p-s-pos, w3-p-s-num
  334.   ;; Depends on case-fold-search being t.
  335.   (defsubst w3-expand-entity-at-point-maybe ()
  336.     ;; We are looking at a &.
  337.     ;; Only &A or  or &#A syntax is special.
  338.     (cond
  339.      ((and (looking-at "&\\([a-z][-a-z0-9.]*\\)[\ ;\n]?") ; \n should be \r
  340.            ;; We are looking at a general entity reference, maybe undefined.
  341.            (setq w3-p-s-entity
  342.                  (get 
  343.                   (intern (buffer-substring (match-beginning 1) (match-end 1)))
  344.                   'html-entity-expansion)))
  345.  
  346.       ;; If the reference was undefined, then for SGML, we should really
  347.       ;; issue a warning and delete the reference.  However, the HTML
  348.       ;; standard (contradicting the SGML standard) says to leave the
  349.       ;; undefined reference in the text.
  350.     
  351.       ;; We are looking at a defined general entity reference.
  352.       (replace-match "")
  353.       (cond ((eq 'CDATA (car w3-p-s-entity))
  354.              ;; Leave point after expansion so we don't rescan it.
  355.              (insert (cdr w3-p-s-entity)))
  356.             ((memq (car w3-p-s-entity) '(nil STARTTAG ENDTAG MS MD))
  357.              ;; nil is how I mark ordinary entities.
  358.              ;; The replacement text gets rescanned for all of these.
  359.              (setq w3-p-s-pos (point))
  360.              (insert (cdr (assq (car w3-p-s-entity)
  361.                                 '((nil . "")
  362.                                   (STARTTAG . "<")
  363.                                   (ENDTAG . "</")
  364.                                   (MS . "<![")
  365.                                   (MD . "<!"))))
  366.                      (cdr w3-p-s-entity)
  367.                      (cdr (assq (car w3-p-s-entity)
  368.                                 '((nil . "")
  369.                                   (STARTTAG . ">")
  370.                                   (ENDTAG . ">")
  371.                                   (MS . "]]>")
  372.                                   (MD . ">")))))
  373.              (goto-char w3-p-s-pos)
  374.              ;; *** Strictly speaking, if we parse anything from the
  375.              ;; replacement text, it must end before the end of the
  376.              ;; replacement text.
  377.              )
  378.             ((eq 'SDATA (car w3-p-s-entity))
  379.              (insert "[Unimplemented SDATA \"%s\"]" (cdr w3-p-s-entity)))
  380.             ((eq 'PI (car w3-p-s-entity))
  381.              ;; We are currently ignoring processing instructions.
  382.              ;; *** Strictly speaking, we should issue a warning if this
  383.              ;; occurs in a attribute value.
  384.              )
  385.             (t
  386.              ;; *** We don't handle external entities yet.
  387.              (error "[Unimplemented entity: \"%s\"]" w3-p-s-entity))))
  388.    
  389.      ((looking-at "&#[0-9][0-9]*\\([\   ;\n]?\\)") ; \n should be \r
  390.       ;; We are looking at a numeric character reference.
  391.       ;; Ensure the number is already terminated by a semicolon or carriage
  392.       ;; return so we can use "read" to get it as a number quickly.
  393.       (cond ((= (match-beginning 1) (match-end 1))
  394.              ;; This is very uncommon, so we don't have to be quick here but
  395.              ;; rather correct.
  396.              (save-excursion
  397.                (goto-char (match-end 0)) ; same as match-end 1
  398.                (insert ?\;))
  399.              ;; Set up the match data properly
  400.              (looking-at "&#[0-9][0-9]*;")))
  401.       (forward-char 2)
  402.       (setq w3-p-s-num (read (current-buffer)))
  403.       ;; Always leave point after the expansion of a numeric
  404.       ;; character reference, like it were a CDATA entity.
  405.       (replace-match "")
  406.       ;; char-to-string will hopefully do something useful with characters
  407.       ;; larger than 255.  I think in MULE it does.  Is this true?
  408.       ;; Bill wants to call w3-resolve-numeric-entity here, but I think
  409.       ;; that functionality belongs in char-to-string.
  410.       ;; The largest valid character in the I18N version of HTML is 65533.
  411.       ;; ftp://ds.internic.net/internet-drafts/draft-ietf-html-i18n-01.txt
  412.       ;; wrongo!  Apparently, mule doesn't do sane things with char-to-string
  413.       ;; -wmp 7/9/96
  414.       (let ((repl (cdr-safe (assq w3-p-s-num w3-invalid-sgml-char-replacement))))
  415.             (insert (or repl (mule-make-iso-character w3-p-s-num)))))
  416.      ((looking-at "&#\\(re\\|rs\\|space\\|tab\\)[\ ;\n]?") ; \n should be \r
  417.       (replace-match (assq (upcase (char-after (+ 3 (point))))
  418.                            '(;; *** Strictly speaking, record end should be
  419.                              ;; carriage return.
  420.                              (?E . "\n") ; RE
  421.                              ;; *** And record start should be line feed.
  422.                              (?S . "")  ; RS
  423.                              (?P . " ") ; SPACE
  424.                              (?A . "\t")))) ; TAB
  425.       ;; Leave point after the expansion of a character reference, so it
  426.       ;; doesn't get rescanned.
  427.       ;; *** Strictly speaking, we should issue a warning for &#foo; if foo
  428.       ;; is not a function character in the SGML declaration.
  429.       )
  430.    
  431.      ((eq ?& (char-after (point)))
  432.       ;; We are either looking at an undefined reference or a & that does
  433.       ;; not start a reference (in which case we should not have been called).
  434.       ;; Skip over the &.
  435.       (forward-char 1))
  436.    
  437.      (t
  438.       ;; What is the code doing calling us if we're not looking at a "&"?
  439.       (error "this should never happen"))))
  440.  
  441.   )
  442.  
  443.  
  444. ;;;
  445. ;;; Syntax table used in markup declarations.
  446. ;;;
  447.  
  448. (defvar w3-sgml-md-syntax-table
  449.   (let ((table (make-syntax-table))
  450.         (items '(
  451.                  (0   "."    255)       ; clear everything
  452.                  (?\r " ")
  453.                  (?\t " ")
  454.                  (?\n " ")
  455.                  (32  " ")              ; space
  456.                  (?<  "\(>")
  457.                  (?>  "\)<")
  458.                  (?\( "\(\)")
  459.                  (?\) "\)\(")
  460.                  (?\[ "\(\]")
  461.                  (?\] "\)\[")
  462.                  (?\" "\"")
  463.                  (?\' "\"")
  464.                  (?a  "w"    ?z)
  465.                  (?A  "w"    ?Z)
  466.                  (?0  "w"    ?9)
  467.                  (?.  "w")
  468.                  ;; "-" can be a character in a NAME, but it is also used in
  469.                  ;; "--" as both a comment start and end within SGML
  470.                  ;; declarations ("<!"  ... ">").  In HTML, it is only used
  471.                  ;; as a NAME character in the parameter entities
  472.                  ;; Content-Type, HTTP-Method, and style-notations and in
  473.                  ;; the attribute name http-equiv and in the notation names
  474.                  ;; dsssl-lite and w3c-style.  We would like to be able to
  475.                  ;; train Emacs to skip over these kinds of comments with
  476.                  ;; forward-sexp and backward-sexp.  Is there any way to
  477.                  ;; teach Emacs how to do this?  It doesn't seem to be the
  478.                  ;; case.
  479.                  (?-  "w")
  480.                  )))
  481.     (while items
  482.       (let* ((item (car items))
  483.              (char (car item))
  484.              (syntax (car (cdr item)))
  485.              (bound (or (car-safe (cdr-safe (cdr item)))
  486.                         char)))
  487.         (while (<= char bound)
  488.           (modify-syntax-entry char syntax table)
  489.           (setq char (1+ char))))
  490.       (setq items (cdr items)))
  491.     table)
  492.   "A syntax table for parsing SGML markup declarations.")
  493.  
  494.  
  495. ;;;
  496. ;;; Element information data type.
  497. ;;;
  498.  
  499. ;;   The element information data type is used in two ways:
  500. ;;
  501. ;;     * To store the DTD, there is one element record for each element in
  502. ;;       the DTD.
  503. ;;
  504. ;;     * To store information for open elements in the current parse tree.
  505. ;;       Each such element is initialized by copying the element record
  506. ;;       from the DTD.  This means that values in the fields can not be
  507. ;;       destructively altered, although of course the fields can be
  508. ;;       changed.
  509.  
  510. ;;   The cells in this vector are:
  511. ;;
  512. ;;   name: the element's name (a generic identifier).
  513. ;;
  514. ;;   end-tag-name: a symbol whose name should be the result of prefixing
  515. ;;   the generic-identifier with a slash.  This is a convenience value for
  516. ;;   interfacing with the display engine which expects a stream of start
  517. ;;   and end tags in this format rather than a tree.
  518. ;;
  519. ;;   content-model: a data structure describing what elements or character
  520. ;;   data we expect to find within this element.  This is either a symbol
  521. ;;   listed here:
  522. ;;
  523. ;;     EMPTY: no content, no end-tag allowed.
  524. ;;     CDATA: all data characters until "</[a-z]" is seen.
  525. ;;     XCDATA: special non-SGML-standard mode which includes all data
  526. ;;       characters until "</foo" is seen where "foo" is the name of this
  527. ;;       element. (for XMP and LISTING)
  528. ;;     XXCDATA: special non-SGML-standard mode which includes all data
  529. ;;       until end-of-entity (end-of-buffer for us). (for PLAINTEXT)
  530. ;;     RCDATA: all data characters until "</[a-z]" is seen, except that
  531. ;;       entities are expanded first, although the expansions are not
  532. ;;       scanned for end-tags.
  533. ;;     XINHERIT: special non-SGML-standard mode which means to use the
  534. ;;       content model of the containing element instead.
  535. ;;  
  536. ;;   or a vector of this structure:
  537. ;;
  538. ;;     [(INCLUDES INCSPACEP (((TAG ...) . TRANSITION) ...) DEFAULT) ...]
  539. ;;
  540. ;;   where INCLUDES is of the format:
  541. ;;
  542. ;;     (TAG ...)
  543. ;;
  544. ;;   where each TRANSITION is one of these:
  545. ;;
  546. ;;     (ACTION NEW-STATE ERRORP)
  547. ;;     (ACTION NEW-STATE)
  548. ;;     (ACTION)
  549. ;;    
  550. ;;   where DEFAULT is one of these:
  551. ;;
  552. ;;     nil  or  TRANSITION
  553. ;;
  554. ;;   where the meaning of the components is:
  555. ;;
  556. ;;     INCLUDES is a list of tags for which the transition (*include *same
  557. ;;     nil) applies.
  558. ;;
  559. ;;     DEFAULT if non-nil is a transition that should be taken when
  560. ;;     matching any possibility not explicitly listed in another
  561. ;;     TRANSITION, except for data characters containing only whitespace.
  562. ;;
  563. ;;     INCSPACEP specifies how to handle data characters which include
  564. ;;     only whitespace characters.  The value is non-nil to indicate
  565. ;;     (*include *same nil) or nil to indicate (*discard *same nil).
  566. ;;    
  567. ;;     TAG is a symbol corresponding to the start-tag we are looking at,
  568. ;;     or *data when seeing character data that includes at least one
  569. ;;     non-space character.
  570. ;;
  571. ;;     ACTION is one of:
  572. ;;       *close: Close this element and try again using content model of
  573. ;;           enclosing element.  (Note that this does not apply to the
  574. ;;           case of an element being closed by its own end-tag.)
  575. ;;       *include: Process new element as subelement of this one or
  576. ;;           include data characters directly.
  577. ;;       *discard: Discard a start-tag or data characters.
  578. ;;       *retry: Try again after processing NEW-STATE and ERRORP.
  579. ;;       ELEMENT: Open ELEMENT (with default attributes), then try again
  580. ;;           using its content model. 
  581. ;;
  582. ;;     NEW-STATE (optional, default *same) is the index of the state to
  583. ;;     move to after processing the element or one of these:
  584. ;;       *same: no state change occurs.
  585. ;;       *next: change the current state + 1.
  586. ;;     The initial state is 0.  NEW-STATE does not matter if ACTION is
  587. ;;     *close.
  588. ;;    
  589. ;;     ERRORP (optional, default nil) if non-nil indicates this transition
  590. ;;     represents an error.  The error message includes this value if it
  591. ;;     is a string.
  592. ;;
  593. ;;   If no matching transition is found, the default transition is
  594. ;;   (*discard *same "not allowed here").
  595. ;;
  596. ;;   overrides: An alist of pairs of the form (VAR REPLACEP . VALUE).
  597. ;;   When this element is opened, the old value of VAR is saved in the
  598. ;;   undo-list.  If REPLACEP is non-nil, then VAR gets value VALUE,
  599. ;;   otherwise VAR gets value (append VALUE (symbol-value VAR)).  Useful
  600. ;;   values for VAR are:
  601. ;;
  602. ;;     w3-p-d-exceptions: See doc string.
  603. ;;  
  604. ;;     w3-p-d-shortrefs: See doc string.
  605. ;;
  606. ;;     w3-p-d-shortref-chars: See doc string.
  607. ;;
  608. ;;   end-tag-omissible: Whether it is legal to omit the end-tag of this
  609. ;;   element.  If an end-tag is inferred for an element whose end tag is
  610. ;;   not omissible, an error message is given.
  611. ;;
  612. ;;   state: The current state in the content model.  Preset to the initial
  613. ;;   state of 0.
  614. ;;
  615. ;;   undo-list: an alist of of former values of local variables
  616. ;;   of w3-parse-buffer to restore upon closing this element.  Each
  617. ;;   item on the list is of the format (VAR . VALUE-TO-RESTORE). 
  618. ;;
  619. ;;   attributes: an alist of attributes and values.  Each item on
  620. ;;   this list is of the format (ATTRIBUTE-NAME . VALUE).  Each
  621. ;;   ATTRIBUTE-NAME is a symbol and each attribute value is a
  622. ;;   string.
  623. ;;
  624. ;;   content: a list of the accumulated content of the element.  While the
  625. ;;   element is open, the list is in order from latest to earliest,
  626. ;;   otherwise it is in order from earliest to latest.  Each member is
  627. ;;   either a string of data characters or a list of the form (NAME
  628. ;;   ATTRIBUTES CONTENT), where NAME is the subelement's name, ATTRIBUTES
  629. ;;   is an alist of the subelement's attribute names (lowercase symbols)
  630. ;;   and their values (strings), and CONTENT is the subelement's content.
  631.  
  632. (eval-when-compile
  633.  
  634.   (defconst w3-element-fields
  635.     '(name end-tag-name content-model state overrides undo-list
  636.            content attributes end-tag-omissible deprecated))
  637.  
  638.   (let* ((fields w3-element-fields)
  639.          (index (1- (length fields))))
  640.     (while fields
  641.       (let* ((field (symbol-name (car fields)))
  642.              (get-sym (intern (concat "w3-element-" field)))
  643.              (set-sym (intern (concat "w3-set-element-" field))))
  644.         (eval (` (progn
  645.                    (defmacro (, get-sym) (element)
  646.                      (list 'aref element (, index)))
  647.                    (defmacro (, set-sym) (element value)
  648.                      (list 'aset element (, index) value))))))
  649.       (setq fields (cdr fields))
  650.       (setq index (1- index))))
  651.  
  652.   (defmacro w3-make-element ()
  653.     (list 'make-vector (length w3-element-fields) nil))
  654.  
  655.   ;; *** move this to be with DTD declaration.
  656.   (defmacro w3-fresh-element-for-tag (tag)
  657.     (` (copy-sequence
  658.         (or (get (, tag) 'html-element-info)
  659.             (error "unimplemented element %s"
  660.                    (w3-sgml-name-to-string (, tag)))))))
  661.  
  662.   ;; *** move this to be with DTD declaration.
  663.   (defmacro w3-known-element-p (tag)
  664.     (` (get (, tag) 'html-element-info)))
  665.   
  666.   (defsubst w3-sgml-name-to-string (sym)
  667.     (upcase (symbol-name sym)))
  668.   
  669.   )
  670.  
  671.  
  672. ;;;
  673. ;;; Parse tree manipulation.
  674. ;;;
  675.  
  676. ;;    ;; Find the name of the previous element or a substring of the
  677. ;;    ;; preceding data characters.
  678. ;;    (let ((content (w3-element-content (car stack))))
  679. ;;      (while content
  680. ;;        (cond
  681. ;;         ((and (stringp (car content))
  682. ;;               (not (string-match "\\`[ \t\n\r]*\\'" (car content))))
  683. ;;          (setq prior-item (car content))
  684. ;;          ;; Trim trailing whitespace
  685. ;;          (if (string-match "\\(.*[^ \t\n\r]\\)[ \t\n\r]*\\'" prior-item)
  686. ;;              (setq prior-item (substring prior-item 0 (match-end 1))))
  687. ;;          (if (> (length prior-item) 8)
  688. ;;              (setq prior-item (concat "..." (substring prior-item -8))))
  689. ;;          (setq prior-item (w3-quote-for-string prior-item))
  690. ;;          (setq prior-item (concat "\(after " prior-item "\)"))
  691. ;;          (setq content nil))
  692. ;;         ((and (consp (car content))
  693. ;;               (symbolp (car (car content))))
  694. ;;          (setq prior-item
  695. ;;                (concat "\(after "
  696. ;;                        (w3-sgml-name-to-string (car (car content)))
  697. ;;                        "\)"))
  698. ;;          (setq content nil))
  699. ;;         (t
  700. ;;          (setq content (cdr content))))))
  701.  
  702. ;; Only used for HTML debugging.
  703. (defun w3-open-elements-string (&optional skip-count)
  704.   (let* ((stack (nthcdr (or skip-count 0)
  705.                         (cons w3-p-d-current-element
  706.                               w3-p-d-open-element-stack)))
  707.          ;;(prior-item "(at start)")
  708.          result)
  709.     ;; Accumulate the names of the enclosing elements.
  710.     (while stack
  711.       (let ((element (w3-element-name (car stack))))
  712.         (if (eq '*holder element)
  713.             nil
  714.           ;; Only include *DOCUMENT if there are no other elements.
  715.           (if (or (not (eq '*document element))
  716.                   (null result))
  717.               (setq result (cons (w3-sgml-name-to-string element)
  718.                                  result)))))
  719.       (setq stack (cdr stack)))
  720.     (setq result (mapconcat 'identity result ":"))
  721.     (if result
  722.         ;;(concat
  723.          result
  724.         ;; prior-item)
  725.       "[nowhere!]")))
  726.  
  727. ;; *** This doesn't really belong here, but where?
  728. (eval-when-compile
  729.   (defmacro w3-invalid-sgml-chars ()
  730.     "Characters not allowed in an SGML document using the reference
  731. concrete syntax (i.e. HTML).  Returns a string in the format expected by
  732. skip-chars-forward."
  733.     "\000-\010\013\014\016-\037\177-\237"))
  734.  
  735. (eval-when-compile
  736.   ;; Uses:
  737.   ;;   w3-p-d-null-end-tag-enabled, w3-p-d-in-parsed-marked-section,
  738.   ;;   w3-p-d-shortref-chars
  739.   ;; Modifies free variable:
  740.   ;;   w3-p-d-non-markup-chars
  741.   (defsubst w3-update-non-markup-chars ()
  742.     (setq w3-p-d-non-markup-chars
  743.           (concat "^&<"
  744.                   (w3-invalid-sgml-chars)
  745.                   (if w3-p-d-null-end-tag-enabled "/" "")
  746.                   (if w3-p-d-in-parsed-marked-section "]" "")
  747.                   (or w3-p-d-shortref-chars ""))))
  748. )
  749.  
  750. (eval-when-compile
  751.   (w3-p-s-var-def w3-p-s-overrides)
  752.   (w3-p-s-var-def w3-p-s-undo-list)
  753.   (w3-p-s-var-def w3-p-s-var)
  754.   ;; Uses free variables:
  755.   ;;   w3-p-d-non-markup-chars
  756.   ;; Modifies free variables:
  757.   ;;   w3-p-d-current-element, w3-p-d-open-element-stack
  758.   ;; Destroys free variables:
  759.   ;;   w3-p-s-overrides, w3-p-s-undo-list, w3-p-s-var
  760.   (defsubst w3-open-element (tag attributes)
  761.  
  762.     ;; Push new element on stack.
  763.     (setq w3-p-d-open-element-stack (cons w3-p-d-current-element
  764.                                           w3-p-d-open-element-stack))
  765.     (setq w3-p-d-current-element (w3-fresh-element-for-tag tag))
  766.     
  767.     ;; Warn if deprecated or obsolete.
  768.     (if (w3-element-deprecated w3-p-d-current-element)
  769.         (w3-debug-html :outer
  770.           (format "%s element %s."
  771.                   (if (eq 'obsolete
  772.                           (w3-element-deprecated w3-p-d-current-element))
  773.                       "Obsolete"
  774.                     "Deprecated")
  775.                   (w3-sgml-name-to-string
  776.                    (w3-element-name w3-p-d-current-element)))))
  777.     
  778.     ;; Store attributes.
  779.     ;; *** we are not handling #CURRENT attributes (HTML has none).
  780.     (w3-set-element-attributes w3-p-d-current-element attributes)
  781.     ;; *** Handle default attribute values.
  782.     ;; *** Fix the attribute name for unnamed values.  Right now they will
  783.     ;; be in the attribute list as items of the format (VALUE . VALUE) where
  784.     ;; both occurrences of VALUE are the same.  The first one needs to be
  785.     ;; changed to the proper attribute name by consulting the DTD.
  786.     ;; ********************
  787.   
  788.     ;; Handle syntax/semantics overrides of new current element.
  789.     (cond ((w3-element-overrides w3-p-d-current-element)
  790.            (setq w3-p-s-overrides
  791.                  (w3-element-overrides w3-p-d-current-element))
  792.            (setq w3-p-s-undo-list nil)
  793.            (while w3-p-s-overrides
  794.              (setq w3-p-s-var (car (car w3-p-s-overrides)))
  795.              (setq w3-p-s-undo-list
  796.                    (cons (cons w3-p-s-var
  797.                                (symbol-value w3-p-s-var))
  798.                          w3-p-s-undo-list))
  799.              (set w3-p-s-var (if (car (cdr (car w3-p-s-overrides)))
  800.                                  (cdr (cdr (car w3-p-s-overrides)))
  801.                                (append (cdr (cdr (car w3-p-s-overrides)))
  802.                                        (symbol-value w3-p-s-var))))
  803.              ;; *** HACK HACK.
  804.              ;; Magic handling of w3-p-d-shortref-chars.
  805.              (cond ((eq 'w3-p-d-shortref-chars w3-p-s-var)
  806.                     (setq w3-p-s-undo-list
  807.                           (cons (cons 'w3-p-d-non-markup-chars
  808.                                       w3-p-d-non-markup-chars)
  809.                                 w3-p-s-undo-list))
  810.                     (w3-update-non-markup-chars)))
  811.              (setq w3-p-s-overrides (cdr w3-p-s-overrides)))
  812.            (w3-set-element-undo-list w3-p-d-current-element
  813.                                      w3-p-s-undo-list)))
  814.   
  815.     ;; Handle content-model inheritance.  (Very non-SGML!)
  816.     (if (eq 'XINHERIT (w3-element-content-model w3-p-d-current-element))
  817.         (w3-set-element-content-model
  818.          w3-p-d-current-element 
  819.          (w3-element-content-model (car w3-p-d-open-element-stack))))
  820.   
  821.     )
  822.   )
  823.  
  824. ;; The protocol for handing items to the display engine is as follows.
  825. ;;
  826. ;; For an element, send (START-TAG . ATTS), each member of the content,
  827. ;; and (END-TAG . nil) if the element is allowed to have an end tag.
  828. ;;
  829. ;; For data characters, send (text . DATA-CHARACTERS).
  830. ;;
  831. ;; Exceptions:
  832. ;;
  833. ;; For PLAINTEXT, STYLE, XMP, TEXTAREA send:
  834. ;; (START-TAG . ((data . DATA-CHARACTERS) . ATTS)).
  835. ;;
  836. ;; *** This requires somehow eliminating any subelements of the TEXTAREA
  837. ;; element.  TEXTAREA can contain subelements in HTML 3.0.
  838. ;;
  839. ;; For LISTING, send (text . DATA-CHARACTERS).  (Is this really correct or
  840. ;; is this perhaps a bug in the old parser?)  I'm ignoring this for now.
  841.  
  842. (eval-when-compile
  843.   (w3-p-s-var-def w3-p-s-undo-list)
  844.   (w3-p-s-var-def w3-p-s-content)
  845.   (w3-p-s-var-def w3-p-s-end-tag)
  846.   ;; Modifies free variables:
  847.   ;;   w3-p-d-current-element, w3-p-d-open-element-stack
  848.   ;; Accesses free variables:
  849.   ;;   w3-p-d-tag-name, w3-p-d-end-tag-p
  850.   ;; Destroys free variables:
  851.   ;;   w3-p-s-undo-list, w3-p-s-content, w3-p-s-end-tag
  852.   (defsubst w3-close-element (&optional inferred)
  853.     ;; inferred: non-nil if the end-tag of the current element is being
  854.     ;; inferred due to the presence of content not allowed in the current
  855.     ;; element.  If t, then the tag causing this is in w3-p-d-tag-name and
  856.     ;; w3-p-d-end-tag-p.
  857.     ;; (OLD: ... otherwise it is a symbol indicating the start-tag
  858.     ;; of an element or *data or *space indicating data characters.)
  859.     
  860.     (cond ((and inferred
  861.                 (not (w3-element-end-tag-omissible w3-p-d-current-element)))
  862.            (w3-debug-html
  863.              (format "</%s> end-tag not omissible (required due to %s)"
  864.                      (w3-sgml-name-to-string
  865.                       (w3-element-name w3-p-d-current-element))
  866.                      (cond ((eq t inferred)
  867.                             (format (if w3-p-d-end-tag-p
  868.                                         "</%s> end-tag"
  869.                                       "start-tag for %s")
  870.                                     (w3-sgml-name-to-string
  871.                                      w3-p-d-tag-name)))
  872.                            ;; *** Delete this functionality?
  873.                            ((memq inferred '(*space *data))
  874.                             "data characters")
  875.                            ((symbolp inferred)
  876.                             (format "start-tag for %s"
  877.                                     (w3-sgml-name-to-string inferred)))
  878.                            )))))
  879.     
  880.     ;; Undo any variable bindings of this element.
  881.     (cond ((w3-element-undo-list w3-p-d-current-element)
  882.            (setq w3-p-s-undo-list
  883.                  (w3-element-undo-list w3-p-d-current-element))
  884.            (while w3-p-s-undo-list
  885.              (set (car (car w3-p-s-undo-list))
  886.                   (cdr (car w3-p-s-undo-list)))
  887.              (setq w3-p-s-undo-list (cdr w3-p-s-undo-list)))))
  888.   
  889.     (setq w3-p-s-end-tag
  890.           (w3-element-end-tag-name w3-p-d-current-element))
  891.   
  892.     ;; Fix up the content of the current element in preparation for putting
  893.     ;; it in the parent.
  894.     ;; Remove trailing newline from content, if there is one, otherwise send
  895.     ;; any trailing data character item to display engine.
  896.     (setq w3-p-s-content (w3-element-content w3-p-d-current-element))
  897.     (cond ((null w3-p-s-content))
  898.           ((equal "\n" (car w3-p-s-content))
  899.            (setq w3-p-s-content (cdr w3-p-s-content)))
  900.           )
  901.   
  902.     (cond ;; *** Handle LISTING the way the old parser did.
  903.           ((eq 'EMPTY (w3-element-content-model w3-p-d-current-element))
  904.            ;; Do nothing, can't have an end tag.
  905.            )
  906.           (t
  907.            ;; Normal case.
  908.            (if (null w3-p-s-content)
  909.                (w3-debug-html
  910.                  :bad-style :outer
  911.                  ;; Don't warn for empty TD elements or empty A elements
  912.                  ;; with no HREF attribute.
  913.                  ;; *** Crude hack that should really be encoded in the
  914.                  ;; element database somehow.
  915.                  (if (or (not (memq (w3-element-name w3-p-d-current-element)
  916.                                     '(a td)))
  917.                          (assq 'href
  918.                                (w3-element-attributes w3-p-d-current-element)))
  919.                      (format "Empty %s element."
  920.                              (w3-sgml-name-to-string
  921.                               (w3-element-name w3-p-d-current-element))))))))
  922.     
  923.     ;; Put the current element in the proper place in its parent.
  924.     ;; This will cause an error if we overpop the stack.
  925.     (w3-set-element-content
  926.      (car w3-p-d-open-element-stack) 
  927.      (cons (list (w3-element-name w3-p-d-current-element)
  928.                  (w3-element-attributes w3-p-d-current-element)
  929.                  (nreverse w3-p-s-content))
  930.            (w3-element-content (car w3-p-d-open-element-stack))))
  931.   
  932.     ;; Pop the stack.
  933.     (setq w3-p-d-current-element (car w3-p-d-open-element-stack))
  934.     (setq w3-p-d-open-element-stack (cdr w3-p-d-open-element-stack)))
  935.  
  936.   )
  937.  
  938.  
  939. ;;;
  940. ;;; A pseudo-DTD for HTML.
  941. ;;;
  942.  
  943. (eval-when-compile
  944.   ;; This works around the following bogus compiler complaint:
  945.   ;;   While compiling the end of the data in file w3-parse.el:
  946.   ;;     ** the function w3-expand-parameters is not known to be defined.
  947.   ;; This is a bogus error.  Anything of this form will trigger this message:
  948.   ;;   (eval-when-compile (defun xyzzy () (xyzzy)))
  949.   (defun w3-expand-parameters (pars data) nil))
  950.  
  951. (eval-when-compile
  952.   (defun w3-expand-parameters (pars data)
  953.     (cond ((null data)
  954.            nil)
  955.           ((consp data)
  956.            ;; This has to be written carefully to avoid exceeding the
  957.            ;; maximum lisp function call nesting depth.
  958.            (let (result)
  959.              (while (consp data)
  960.                (let ((car-exp (w3-expand-parameters pars (car data))))
  961.                  (setq result
  962.                        (if (and (symbolp (car data))
  963.                                 (not (eq car-exp (car data)))
  964.                                 ;; An expansion occurred.
  965.                                 (listp car-exp))
  966.                            ;; The expansion was a list, which we splice in.
  967.                            (condition-case err
  968.                                (append (reverse car-exp) result)
  969.                              (wrong-type-argument
  970.                               (if (eq 'listp (nth 1 err))
  971.                                   ;; Wasn't really a "list" since the last
  972.                                   ;; cdr wasn't nil, so don't try to splice
  973.                                   ;; it in.
  974.                                   (cons car-exp result)
  975.                                 (signal (car err) (cdr err)))))
  976.                          (cons car-exp result))))
  977.                (setq data (cdr data)))
  978.              (append (nreverse result)
  979.                      (w3-expand-parameters pars data))))
  980.           ((symbolp data)
  981.            (let ((sym-exp (cdr-safe (assq data pars))))
  982.              (if sym-exp
  983.                  (w3-expand-parameters pars sym-exp)
  984.                data)))
  985.           ((vectorp data)
  986.            (let ((i 0)
  987.                  (result (copy-sequence data)))
  988.              (while (< i (length data))
  989.                (aset result i
  990.                      (w3-expand-parameters pars (aref data i)))
  991.                (setq i (1+ i)))
  992.              result))
  993.           (t
  994.            data))))
  995.  
  996. (eval-when-compile
  997.   (defun w3-unfold-dtd (items)
  998.     (let (result)
  999.       (while items
  1000.         (let* ((item (car items))
  1001.                (names (car item))
  1002.                (content-model
  1003.                 (or (cdr-safe (assq 'content-model item))
  1004.                     (error "impossible")))
  1005.                (overrides (cdr-safe (assq 'overrides item)))
  1006.                (end-tag-omissible
  1007.                 (or (cdr-safe (assq 'end-tag-omissible item))
  1008.                     ;; *** Is this SGML standard?
  1009.                     (eq 'EMPTY content-model)))
  1010.                (deprecated (cdr-safe (assq 'deprecated item)))
  1011.                element
  1012.                name)
  1013.           (while names
  1014.             (setq name (car names))
  1015.             (setq names (cdr names))
  1016.  
  1017.             ;; Create and initialize the element information data
  1018.             ;; structure.
  1019.             (setq element (w3-make-element))
  1020.             (w3-set-element-name element name)
  1021.             (w3-set-element-end-tag-name
  1022.              element 
  1023.              (intern (concat "/" (symbol-name name))))
  1024.             (w3-set-element-state element 0)
  1025.             (w3-set-element-content-model element content-model)
  1026.             (w3-set-element-end-tag-omissible element end-tag-omissible)
  1027.             
  1028.             (or (memq deprecated '(nil t obsolete))
  1029.                 (error "impossible"))
  1030.             (w3-set-element-deprecated element deprecated)
  1031.             
  1032.             ;; Inclusions and exclusions are specified differently in the
  1033.             ;; human-coded DTD than in the format the implementation uses.
  1034.             ;; The human-coded version is designed to be easy to edit and to
  1035.             ;; work with w3-expand-parameters while the internal version is
  1036.             ;; designed to be fast.  We have to translate here.  This work
  1037.             ;; is repeated for every element listed in `names' so that the
  1038.             ;; exclusion exception error messages can be accurate.
  1039.             (let ((inclusions (cdr-safe (assq 'inclusions item)))
  1040.                   (exclusions (cdr-safe (assq 'exclusions item)))
  1041.                   (exclusion-mode '*close)
  1042.                   (exclusion-message 
  1043.                    (format "%s exclusion" (w3-sgml-name-to-string name)))
  1044.                   exceptions)
  1045.               (while inclusions
  1046.                 (setq exceptions (cons (cons (car inclusions)
  1047.                                              '(*include *same nil))
  1048.                                        exceptions))
  1049.                 (setq inclusions (cdr inclusions)))
  1050.               (while exclusions
  1051.                 (cond ((memq (car exclusions) '(*discard *include *close))
  1052.                        (setq exclusion-mode (car exclusions)))
  1053.                       ((stringp (car exclusions))
  1054.                        (setq exclusion-message (car exclusions)))
  1055.                       (t
  1056.                        (setq exceptions (cons (list (car exclusions)
  1057.                                                     exclusion-mode
  1058.                                                     '*same
  1059.                                                     exclusion-message)
  1060.                                               exceptions))))
  1061.                 (setq exclusions (cdr exclusions)))
  1062.               (let ((overrides (if exceptions
  1063.                                    (cons (cons 'w3-p-d-exceptions
  1064.                                                (cons nil exceptions))
  1065.                                          overrides)
  1066.                                  overrides)))
  1067.                 (w3-set-element-overrides element overrides)))
  1068.             
  1069.             (setq result (cons (cons name element) result))))
  1070.         (setq items (cdr items)))
  1071.       result)))
  1072.  
  1073. ;; Load the HTML DTD.
  1074. ;; <URL:ftp://ds.internic.net/rfc/rfc1866.txt>
  1075. ;; *** Be sure to incorporate rfc1867 when attribute-checking is added.
  1076. ;; *** Write function to check sanity of the content-model forms.
  1077. ;; *** I18N: Add Q, BDO, SPAN
  1078. (mapcar
  1079.  (function
  1080.   (lambda (pair)
  1081.     (put (car pair) 'html-element-info (cdr pair))))
  1082.  ;; The purpose of this complexity is to speed up loading by
  1083.  ;; pre-evaluating as much as possible at compile time.
  1084.  (eval-when-compile
  1085.    (w3-unfold-dtd
  1086.     (w3-expand-parameters
  1087.      '(
  1088.        (%headempty . (link base meta range))
  1089.        (%headmisc . (script))
  1090.        (%head-deprecated . (nextid))
  1091.  
  1092.        ;; client-side imagemaps
  1093.        (%imagemaps . (area map))
  1094.        (%input.fields . (input select textarea keygen label))
  1095.        ;; special action is taken for %text inside %body.content in the
  1096.        ;; content model of each element.
  1097.        (%body.content . (%heading %block style hr div address %imagemaps))
  1098.  
  1099.        (%heading . (h1 h2 h3 h4 h5 h6))
  1100.  
  1101.        ;; Emacs-w3 extensions
  1102.        (%emacsw3-crud  . (pinhead flame cookie yogsothoth hype peek))
  1103.  
  1104.        (%block . (p %list dl form %preformatted 
  1105.                     %blockquote isindex fn table fig note
  1106.                     multicol center %block-deprecated %block-obsoleted))
  1107.        (%list . (ul ol))
  1108.        (%preformatted . (pre))
  1109.        (%blockquote . (bq))
  1110.        (%block-deprecated . (dir menu blockquote))
  1111.        (%block-obsoleted . (xmp listing))
  1112.        
  1113.        ;; Why is IMG in this list?
  1114.        (%pre.exclusion . (*include img *discard tab math big small sub sup))
  1115.        
  1116.        (%text . (*data b %notmath sub sup %emacsw3-crud %input.fields))
  1117.        (%notmath . (%special %font %phrase %misc))
  1118.        (%font . (i u s strike tt big small sub sup font
  1119.                    roach secret wired)) ;; B left out for MATH
  1120.        (%phrase . (em strong dfn code samp kbd var cite blink))
  1121.        (%special . (a nobr img applet object font basefont br script style map math tab span bdo))
  1122.        (%misc . (q lang au person acronym abbrev ins del))
  1123.        
  1124.        (%formula . (*data %math))
  1125.        (%math . (box above below %mathvec root sqrt array sub sup
  1126.                      %mathface))
  1127.        (%mathvec . (vec bar dot ddot hat tilde))
  1128.        (%mathface . (b t bt))
  1129.  
  1130.        (%mathdelims . (over atop choose left right of))
  1131.  
  1132.        ;; What the hell?  This takes BODYTEXT?????  No way!
  1133.        (%bq-content-model . [(nil
  1134.                               nil
  1135.                               (((bodytext) *include *next))
  1136.                               (bodytext *next))
  1137.                              (nil
  1138.                               nil
  1139.                               (((credit) *include *next))
  1140.                               nil)
  1141.                              (nil nil nil nil)
  1142.                              ])
  1143.  
  1144.        ;; non-default bad HTML handling.
  1145.        (%in-text-ignore . ((p %heading) *discard *same error))
  1146.        )
  1147.      '(
  1148.        ;; A dummy element that will contain *document.
  1149.        ((*holder)
  1150.         (content-model . [(nil nil nil nil)]))
  1151.        ;; The root of the parse tree.  We start with a pseudo-element
  1152.        ;; named *document for convenience.
  1153.        ((*document)
  1154.         (content-model . [(nil nil (((html) *include *next)) (html *next))
  1155.                           (nil
  1156.                            nil
  1157.                            nil
  1158.                            (*include *same "after document end"))])
  1159.         (end-tag-omissible . t))
  1160.        ;; HTML O O (HEAD, BODY)
  1161.        ((html)
  1162.         (content-model . [(nil
  1163.                            nil
  1164.                            (((head) *include *next))
  1165.                            (head *next))
  1166.                           (nil
  1167.                            nil
  1168.                            (((body) *include *next)
  1169.                             ;; Netscape stuff
  1170.                             ((frameset) *include 4)
  1171.                             )
  1172.                            (body *next))
  1173.                           (nil
  1174.                            nil
  1175.                            (((plaintext) *include *next))
  1176.                            (*retry *next))
  1177.                           (nil
  1178.                            nil
  1179.                            nil
  1180.                            (*include *same "after BODY"))
  1181.                           (nil
  1182.                            nil
  1183.                            nil
  1184.                            (*include *same "after FRAMESET"))
  1185.                           ])
  1186.         (end-tag-omissible . t))
  1187.        ((head)
  1188.         (content-model . [((title isindex %headempty %headmisc
  1189.                                   style %head-deprecated)
  1190.                            nil
  1191.                            nil
  1192.                            ;; *** Should only close if tag can
  1193.                            ;; legitimately follow head.  So many can that
  1194.                            ;; I haven't bothered to enumerate them.
  1195.                            (*close))])
  1196.         (end-tag-omissible . t))
  1197.        ;; SCRIPT - - (#PCDATA)
  1198.        ((script)
  1199.         (content-model . XCDATA         ; not official, but allows
  1200.                                         ; comment hiding of script, and also
  1201.                                         ; idiots that use '</' in scripts.
  1202.                        ))
  1203.        ;; TITLE - - (#PCDATA)
  1204.        ((title)
  1205.         (content-model . RCDATA         ; not official
  1206.                        ;; [((*data) include-space nil nil)]
  1207.                        ))
  1208.        ;; STYLE - O (#PCDATA)
  1209.        ;; STYLE needs to be #PCDATA to allow omitted end tag.  Bleagh.
  1210.        ((style)
  1211.         (content-model . CDATA)
  1212.         (end-tag-omissible . t))
  1213.        ((body)
  1214.         (content-model . [((banner) nil nil (*retry *next))
  1215.                           ((bodytext) nil nil (bodytext *next))
  1216.                           (nil nil (((plaintext) *close)) nil)])
  1217.         (inclusions . (spot))
  1218.         (end-tag-omissible . t))
  1219.        ;; Do I really want to include BODYTEXT?  It has something to do
  1220.        ;; with mixed content screwing things up, and I don't understand
  1221.        ;; it.  Wait!  It's used by BQ!
  1222.        ((bodytext)
  1223.         (content-model . [((%body.content)
  1224.                            nil
  1225.                            ;; Push <P> before data characters.  Non-SGML.
  1226.                            (((%text) p)
  1227.                             ;; Some stupid sites put meta tags in the
  1228.                             ;; middle of their documents.  Sigh.
  1229.                             ;; Allow it, but bitch and moan.
  1230.                             ((meta) *include *same "not allowed here")
  1231.                             ;; Closing when seeing CREDIT is a stupidity
  1232.                             ;; caused by BQ's sharing of BODYTEXT.  BQ
  1233.                             ;; should have its own BQTEXT.
  1234.                             ((credit plaintext) *close))
  1235.                            nil)
  1236.                           ])
  1237.         (end-tag-omissible . t))
  1238.        ((div banner center multicol)
  1239.         (content-model . [((%body.content)
  1240.                            nil
  1241.                            ;; Push <P> before data characters.  Non-SGML.
  1242.                            (((%text) p))
  1243.                            nil)]))
  1244.        ((address)
  1245.         (content-model . [((p)
  1246.                            nil
  1247.                            ;; Push <P> before data characters.  Non-SGML.
  1248.                            (((%text) p))
  1249.                            nil)]))
  1250.        ((%heading)
  1251.         (content-model . [((%text)
  1252.                            include-space
  1253.                            ((%in-text-ignore))
  1254.                            nil)]))
  1255.        ((span bdo)
  1256.         (content-model . [((%text)
  1257.                            include-space
  1258.                            nil
  1259.                            nil)])
  1260.         )
  1261.        ((p)
  1262.         (content-model . [((%text)
  1263.                            include-space
  1264.                            nil
  1265.                            ;; *** Should only close if tag can
  1266.                            ;; legitimately follow P.  So many can that I
  1267.                            ;; don't bother to enumerate here.
  1268.                            (*close))])
  1269.         (end-tag-omissible . t))
  1270.        ((ul ol)
  1271.         (content-model . [((lh)
  1272.                            nil
  1273.                            (((li) *include *next))
  1274.                            (*retry *next))
  1275.                           ((p)
  1276.                            nil
  1277.                            nil
  1278.                            (*retry *next))
  1279.                           ((li)
  1280.                            nil
  1281.                            ;; Push <LI> before data characters or block
  1282.                            ;; elements.
  1283.                            ;; Non-SGML.
  1284.                            (;; ((p) b *same nil)
  1285.                             ((%text %block) li *same error))
  1286.                            nil)]))
  1287.        ((lh)
  1288.         (content-model . [((%text)
  1289.                            include-space
  1290.                            (((dd dt li) *close)
  1291.                             (%in-text-ignore))
  1292.                            nil)])
  1293.         (end-tag-omissible . t))
  1294.        ((dir menu)
  1295.         (content-model . [((li)
  1296.                            nil
  1297.                            (((%text) li *same error))
  1298.                            nil)])
  1299.         (exclusions . (%block)))
  1300.        ((li)
  1301.         (content-model . [((%block)
  1302.                            nil
  1303.                            (((li) *close)
  1304.                             ;; Push <P> before data characters.  Non-SGML.
  1305.                             ((%text) p))
  1306.                            nil)])
  1307.         (end-tag-omissible . t)
  1308.         ;; Better bad HTML handling.
  1309.         ;; Technically, there are a few valid documents that this will
  1310.         ;; hose, because you can have H1 inside FORM inside LI.  However,
  1311.         ;; I don't think that should be allowed anyway.
  1312.         (exclusions . (*discard "not allowed here" %heading)))
  1313.        ((dl)
  1314.         (content-model . [((lh)
  1315.                            nil
  1316.                            (((dt dd) *include *next))
  1317.                            (*retry *next))
  1318.                           ((dt dd)
  1319.                            nil
  1320.                            ;; Push <DD> before data characters or block
  1321.                            ;; items.
  1322.                            ;; Non-SGML.
  1323.                            (((%text %block) dd *same error))
  1324.                            nil)]))
  1325.        ((dt)
  1326.         (content-model . [((%text)
  1327.                            include-space
  1328.                            (((dd dt) *close)
  1329.                             (%in-text-ignore))
  1330.                            nil)])
  1331.         (end-tag-omissible . t))
  1332.        ;; DD is just like LI, but we treat it separately because it can be
  1333.        ;; followed by a different set of elements.
  1334.        ((dd)
  1335.         (content-model . [((%block)
  1336.                            nil
  1337.                            (((dt dd) *close)
  1338.                             ;; Push <P> before data characters.  Non-SGML.
  1339.                             ((%text) p))
  1340.                            nil)])
  1341.         (end-tag-omissible . t)
  1342.         ;; See comment with LI.
  1343.         (exclusions . (*discard "not allowed here" %heading)))
  1344.        ((pre)
  1345.         (content-model . [((%text hr)
  1346.                            include-space
  1347.                            ((%in-text-ignore))
  1348.                            nil)])
  1349.         (exclusions . (%pre.exclusion)))
  1350.        ;; BLOCKQUOTE deprecated, BQ okay
  1351.        ((bq)
  1352.         (content-model . %bq-content-model))
  1353.        ((blockquote)
  1354.         (content-model . %bq-content-model)
  1355.         ;; BLOCKQUOTE is deprecated in favor of BQ in the HTML 3.0 DTD.
  1356.         ;; However, BQ is not even mentioned in the HTML 2.0 DTD.  So I
  1357.         ;; don't think we can enable this yet:
  1358.         ;;(deprecated . t)
  1359.         )
  1360.        ((fn note)
  1361.         (content-model . [((%body.content)
  1362.                            nil
  1363.                            ;; Push <P> before data characters.  Non-SGML.
  1364.                            (((%text) p))
  1365.                            nil)]))
  1366.        ((fig)
  1367.         (content-model . [((overlay) nil nil (*retry *next))
  1368.                           (nil
  1369.                            nil
  1370.                            (((caption) *include *next))
  1371.                            (*retry *next))
  1372.                           (nil
  1373.                            nil
  1374.                            (((figtext) *include *next)
  1375.                             ((credit) *retry *next))
  1376.                            ;; *** Should only do this for elements that
  1377.                            ;; can be in FIGTEXT.
  1378.                            (figtext *next))
  1379.                           (nil nil (((credit) *include *next)) nil)
  1380.                           (nil nil nil nil)]))
  1381.        ((caption credit)
  1382.         (content-model . [((%text)
  1383.                            nil
  1384.                            ((%in-text-ignore))
  1385.                            nil)]))
  1386.        ((figtext)
  1387.         (content-model . [((%body.content)
  1388.                            nil
  1389.                            ;; Push <P> before data characters.  Very non-SGML.
  1390.                            (((%text) p)
  1391.                             ((credit) *close))
  1392.                            nil)])
  1393.         (end-tag-omissible . t))
  1394.        ((%emacsw3-crud basefont)
  1395.         (content-model . EMPTY))
  1396.        ;; FORM - - %body.content -(FORM) +(INPUT|KEYGEN|SELECT|TEXTAREA)
  1397.        ((form)
  1398.         ;; Same as BODY.  Ugh!
  1399.         (content-model . [((%body.content %text)
  1400.                            nil
  1401.                            ;; Push <P> before data characters.  Non-SGML.
  1402.                            nil
  1403.                            nil)])
  1404.         (exclusions . (form))
  1405.         (inclusions . (input select textarea keygen label)))
  1406.        ;; *** Where is the URL describing this?
  1407.        ((label)
  1408.         (content-model . [((%text)
  1409.                            include-space
  1410.                            nil
  1411.                            nil)])
  1412.         ;; *** These are already included, no need to repeat.
  1413.         ;;(inclusions . (input select textarea))
  1414.         ;; *** Is a LABEL allowed inside a LABEL?  I assume no.
  1415.         (exclusions . (label))
  1416.         ;; The next line just does the default so is unneeded:
  1417.         ;;(end-tag-omissible . nil)
  1418.         )
  1419.        ;; SELECT - - (OPTION+) -(INPUT|KEYGEN|TEXTAREA|SELECT)>
  1420.        ;; *** This should be -(everything).
  1421.        ((select)
  1422.         (content-model . [((option) nil nil nil)])
  1423.         (exclusions . (input label select keygen textarea)))
  1424.        ;; option - O (#PCDATA)
  1425.        ;; needs to be #PCDATA to allow omitted end tag.
  1426.        ((option)
  1427.         ;; I'd like to make this RCDATA to avoid problems with inclusions
  1428.         ;; like SPOT, but that would conflict with the omitted end-tag, I
  1429.         ;; think.
  1430.         (content-model . [((*data)
  1431.                            include-space
  1432.                            (((option) *close))
  1433.                            nil)])
  1434.         (end-tag-omissible . t))
  1435.        ;; TEXTAREA - - (#PCDATA) -(INPUT|TEXTAREA|KEYGEN|SELECT)
  1436.        ((textarea)
  1437.         ;; Same comment as for OPTION about RCDATA.
  1438.         (content-model . [((*data) include-space nil nil)])
  1439.         (exclusions . (input select label keygen textarea)))
  1440.        ((hr br img isindex input keygen overlay wbr spot tab
  1441.             %headempty %mathdelims)
  1442.         (content-model . EMPTY))
  1443.        ((nextid)
  1444.         (content-model . EMPTY)
  1445.         (deprecated . t))
  1446.        ((a)
  1447.         (content-model . [((%text)
  1448.                            include-space
  1449.                            (((%heading)
  1450.                              *include *same "deprecated inside A")
  1451.                             ;; *** I haven't made up my mind whether this
  1452.                             ;; is a good idea.  It can result in a lot of
  1453.                             ;; bad formatting if the A is *never* closed.
  1454.                             ;;((p) *discard *same error)
  1455.                             )
  1456.                            nil)])
  1457.         (exclusions . (a)))
  1458.        ((b font %font %phrase %misc nobr)
  1459.         (content-model . [((%text)
  1460.                            include-space
  1461.                            ((%in-text-ignore))
  1462.                            nil)]))
  1463.        ((plaintext)
  1464.         (content-model . XXCDATA)
  1465.         (end-tag-omissible . t)
  1466.         (deprecated . obsolete))
  1467.        ((xmp listing)
  1468.         (content-model . XCDATA)
  1469.         (deprecated . obsolete))
  1470.        ;; Latest table spec (as of Nov. 13 1995) is at:
  1471.        ;; <URL:ftp://ds.internic.net/internet-drafts/draft-ietf-html-tables-03.txt>
  1472.        ((table)
  1473.         (content-model . [(nil
  1474.                            nil
  1475.                            (((caption) *include *next)
  1476.                             ((%text) tr *same error)
  1477.                             ((col colgroup thead tfoot tbody tr) *retry *next))
  1478.                            (*retry *next)) ;error handling
  1479.                           ((col colgroup)
  1480.                            nil
  1481.                            (((thead tfoot tbody tr) *retry *next))
  1482.                            (*retry *next)) ;error handling
  1483.                           (nil
  1484.                            nil
  1485.                            (((thead) *include *next)
  1486.                             ((tfoot tbody tr) *retry *next))
  1487.                            (*retry *next)) ;error handling
  1488.                           (nil
  1489.                            nil
  1490.                            (((tfoot) *include *next)
  1491.                             ((tbody tr) *retry *next))
  1492.                            (*retry *next)) ;error handling
  1493.                           ((tbody)
  1494.                            nil
  1495.                            (((tr) tbody *same)
  1496.                             ((td th) tr *same)
  1497.                             ;; error handling
  1498.                             ((%body.content) tbody *same error))
  1499.                            nil)]))
  1500.        ((colgroup)
  1501.         (content-model . [((col)
  1502.                            nil
  1503.                            (((colgroup thead tfoot tbody tr) *close))
  1504.                            nil)])
  1505.         (end-tag-omissible . t))
  1506.        ((col)
  1507.         (content-model . EMPTY))
  1508.        ((thead)
  1509.         (content-model . [((tr)
  1510.                            nil
  1511.                            (((tfoot tbody) *close)
  1512.                             ;; error handling
  1513.                             ((%body.content) tr *same error))
  1514.                            nil)])
  1515.         (end-tag-omissible . t))
  1516.        ((tfoot tbody)
  1517.         (content-model . [((tr)
  1518.                            nil
  1519.                            (((tbody) *close)
  1520.                             ;; error handling
  1521.                             ((td th) tr *same error)
  1522.                             ((%body.content) tr *same error))
  1523.                            nil)])
  1524.         (end-tag-omissible . t))
  1525.        ((tr)
  1526.         (content-model . [((td th)
  1527.                            nil
  1528.                            (((tr tfoot tbody) *close)
  1529.                             ;; error handling
  1530.                             ((%body.content %text) td *same error))
  1531.                            nil)])
  1532.         (end-tag-omissible . t))
  1533.        ((td th)
  1534.         ;; Arrgh!  Another %body.content!!!  Stupid!!!
  1535.         (content-model . [((%body.content)
  1536.                            nil
  1537.                            (((td th tr tfoot tbody) *close)
  1538.                             ;; Push <P> before data characters.  Non-SGML.
  1539.                             ((%text) p))
  1540.                            nil)])
  1541.         (end-tag-omissible . t))
  1542.        ((math)
  1543.         (content-model . [((*data) include-space nil nil)])
  1544.         (overrides .
  1545.                    ((w3-p-d-shortref-chars t . "\{_^")
  1546.                     (w3-p-d-shortrefs t . (("\\^" . "<sup>")
  1547.                                            ("_" . "<sub>")
  1548.                                            ("{" . "<box>")))))
  1549.         (inclusions . (%math))
  1550.         (exclusions . (%notmath)))
  1551.        ((sup)
  1552.         (content-model . [((%text)
  1553.                            include-space
  1554.                            ((%in-text-ignore))
  1555.                            nil)])
  1556.         (overrides .
  1557.                    ((w3-p-d-shortref-chars t . "\{_^")
  1558.                     (w3-p-d-shortrefs t . (("\\^" . "</sup>")
  1559.                                            ("_" . "<sub>")
  1560.                                            ("{" . "<box>"))))))
  1561.        ((sub)
  1562.         (content-model . [((%text)
  1563.                            include-space
  1564.                            ((%in-text-ignore))
  1565.                            nil)])
  1566.         (overrides .
  1567.                    ((w3-p-d-shortref-chars t . "\{_^")
  1568.                     (w3-p-d-shortrefs t . (("\\^" . "<sup>")
  1569.                                            ("_" . "</sub>")
  1570.                                            ("{" . "<box>"))))))
  1571.        ((box)
  1572.         (content-model . [((%formula)
  1573.                            include-space
  1574.                            (((left) *include 1)
  1575.                             ((over atop choose) *include 2)
  1576.                             ((right) *include 3))
  1577.                            nil)
  1578.                           ((%formula)
  1579.                            include-space
  1580.                            (((over atop choose) *include 2)
  1581.                             ((right) *include 3))
  1582.                            nil)
  1583.                           ((%formula)
  1584.                            include-space
  1585.                            (((right) *include 3))
  1586.                            nil)
  1587.                           ((%formula) include-space nil nil)])
  1588.         (overrides .
  1589.                    ((w3-p-d-shortref-chars t . "{}_^")
  1590.                     (w3-p-d-shortrefs t . (("\\^" . "<sup>")
  1591.                                            ("_" . "<sub>")
  1592.                                            ("{" . "<box>")
  1593.                                            ("}" . "</box>"))))))
  1594.        ((above below %mathvec t bt sqrt)
  1595.         (content-model . [((%formula) include-space nil nil)]))
  1596.        ;; ROOT has a badly-specified content-model in HTML 3.0.
  1597.        ((root)
  1598.         (content-model . [((%formula)
  1599.                            include-space
  1600.                            (((of) *include *next))
  1601.                            nil)
  1602.                           ((%formula) include-space nil nil)]))
  1603.        ((of)
  1604.         (content-model . [((%formula) include-space nil nil)])
  1605.         ;; There is no valid way to infer a missing end-tag for OF.  This
  1606.         ;; is bizarre.
  1607.         (end-tag-omissible . t))
  1608.        ((array)
  1609.         (content-model . [((row) nil nil nil)]))
  1610.        ((row)
  1611.         (content-model . [((item) nil (((row) *close)) nil)])
  1612.         (end-tag-omissible . t))
  1613.        ((item)
  1614.         (content-model . [((%formula)
  1615.                            include-space
  1616.                            (((row item) *close))
  1617.                            nil)])
  1618.         (end-tag-omissible . t))
  1619.        ;; The old parser would look for the </EMBED> end-tag and include
  1620.        ;; the contents between <EMBED> and </EMBED> as the DATA attribute
  1621.        ;; of the EMBED start-tag.  However, it did not require the
  1622.        ;; </EMBED> end-tag and did nothing if it was missing.  This is
  1623.        ;; completely impossible to specify in SGML.
  1624.        ;;
  1625.        ;; See
  1626.        ;; <URL:http://www.eit.com/goodies/lists/www.lists/www-html.1995q3/0603.html>  
  1627.        ;;
  1628.        ;; Questions: Does EMBED require the end-tag?  How does NOEMBED fit
  1629.        ;; into this?  Where can EMBED appear?
  1630.        ;;
  1631.        ;; Nov. 25 1995: a new spec for EMBED (also an I-D):
  1632.        ;; <URL:http://www.cs.princeton.edu/~burchard/www/interactive/>
  1633.        ;;
  1634.        ;; Here is my guess how to code EMBED:
  1635.        ((embed)
  1636.         (content-model . [((noembed) nil nil (*close))]))
  1637.        ((noembed)
  1638.         (content-model . [((%body.content) ; hack hack hack
  1639.                            nil
  1640.                            (((%text) p))
  1641.                            nil)]))
  1642.        ;;
  1643.        ;; FRAMESET is a Netscape thing.
  1644.        ;; <URL:http://www.eit.com/goodies/lists/www.lists/www-html.1995q3/0588.html>
  1645.        ((frameset)
  1646.         (content-model . [((noframes frame frameset) nil nil nil)]))
  1647.        ((noframes)
  1648.         (content-model . [((%body.content)
  1649.                            nil
  1650.                            ;; Push <P> before data characters.  Non-SGML.
  1651.                            (((%text) p))
  1652.                            nil)]))
  1653.        ((frame)
  1654.         (content-model . EMPTY))
  1655.        ;;
  1656.        ;; APPLET is a Java thing.
  1657.        ;; OBJECT is a cougar thing
  1658.        ;; <URL:http://java.sun.com/JDK-beta/filesinkit/README>
  1659.        ((applet object)
  1660.         ;; I really don't want to add another ANY content-model.
  1661.         (content-model . XINHERIT)
  1662.         (inclusions . (param)))
  1663.        ((param)
  1664.         (content-model . EMPTY))
  1665.        ;; backward compatibility with old Java.
  1666.        ((app)
  1667.         (content-model . EMPTY))
  1668.        ;; Client-side image maps.
  1669.        ;; <URL:ftp://ds.internic.net/internet-drafts/draft-seidman-clientsideimagemap-01.txt>
  1670.        ;; *** The only problem is that I don't know in what elements MAP
  1671.        ;; can appear, so none of this is reachable yet.
  1672.        ((map)
  1673.         (content-model . [((area) nil nil nil)]))
  1674.        ((area)
  1675.         (content-model . EMPTY))
  1676.        )))))
  1677.  
  1678.  
  1679. ;;;
  1680. ;;; Omitted tag inference using state transition tables.
  1681. ;;;
  1682.  
  1683. (eval-when-compile
  1684.  
  1685.   (w3-p-s-var-def w3-p-s-includep)
  1686.   (w3-p-s-var-def w3-p-s-state-transitions)
  1687.   (w3-p-s-var-def w3-p-s-transition)
  1688.   (w3-p-s-var-def w3-p-s-tran-list)
  1689.   (w3-p-s-var-def w3-p-s-content-model)
  1690.   (w3-p-s-var-def w3-p-s-except)
  1691.   (w3-p-s-var-def w3-p-s-baseobject)
  1692.   (w3-p-s-var-def w3-p-s-btdt)
  1693.   ;; Uses free variables:
  1694.   ;;   w3-p-d-current-element, w3-p-d-exceptions
  1695.   ;; Destroys free variables:
  1696.   ;;   w3-p-s-includep, w3-p-s-state-transitions, w3-p-s-transition,
  1697.   ;;   w3-p-s-tran-list, w3-p-s-content-model, w3-p-s-except
  1698.   ;; Returns t if the element or data characters should be included.
  1699.   ;; Returns nil if the element or data characters should be discarded.
  1700.   (defsubst w3-grok-tag-or-data (tag-name)
  1701.     (while
  1702.         (cond
  1703.          ((symbolp (setq w3-p-s-content-model
  1704.                          (w3-element-content-model w3-p-d-current-element)))
  1705.           (or (and (memq w3-p-s-content-model
  1706.                          '(CDATA RCDATA XCDATA XXCDATA))
  1707.                    (memq tag-name '(*data *space)))
  1708.               ;; *** Implement ANY.
  1709.               (error "impossible content model lossage"))
  1710.           (setq w3-p-s-includep t)
  1711.           ;; Exit loop.
  1712.           nil)
  1713.          (t
  1714.           ;; We have a complex content model.
  1715.           ;; Cache some data from the element info structure.  Format is:
  1716.           ;;   (INCLUDES INCSPACEP (((TAG ...) . TRANSITION) ...) DEFAULT)
  1717.           (setq w3-p-s-state-transitions
  1718.                 (aref w3-p-s-content-model
  1719.                       (w3-element-state w3-p-d-current-element)))
  1720.         
  1721.           ;; Optimize the common cases.
  1722.           (cond
  1723.            ((eq '*space tag-name)
  1724.             ;; Optimizing the (*space *discard *same nil) transition.
  1725.             (setq w3-p-s-includep (car (cdr w3-p-s-state-transitions)))
  1726.             ;; Don't loop.
  1727.             nil)
  1728.            ((and (not (setq w3-p-s-except
  1729.                             (assq tag-name w3-p-d-exceptions)))
  1730.                  (memq tag-name (car w3-p-s-state-transitions)))
  1731.             ;; Equivalent to a transition of (TAG *include *same nil).
  1732.             ;; So we are done, return t to caller.
  1733.             (setq w3-p-s-includep t)
  1734.             ;; Exit loop.
  1735.             nil)
  1736.            (t
  1737.             ;; The general case.
  1738.             (cond
  1739.              ;; Handle inclusions and exclusions.
  1740.              (w3-p-s-except
  1741.               (setq w3-p-s-transition (cdr w3-p-s-except)))
  1742.              ;; See if the transition is in the complex transitions
  1743.              ;; component.
  1744.              ((progn
  1745.                 (setq w3-p-s-tran-list
  1746.                       (car (cdr (cdr w3-p-s-state-transitions))))
  1747.                 (setq w3-p-s-transition nil)
  1748.                 (while w3-p-s-tran-list
  1749.                   (cond ((memq tag-name (car (car w3-p-s-tran-list)))
  1750.                          ;; We've found a transition.
  1751.                          (setq w3-p-s-transition
  1752.                                (cdr (car w3-p-s-tran-list)))
  1753.                          (setq w3-p-s-tran-list nil))
  1754.                         (t
  1755.                          (setq w3-p-s-tran-list (cdr w3-p-s-tran-list)))))
  1756.                 ;; Check if we found it.
  1757.                 w3-p-s-transition)
  1758.               ;; body of cond clause empty
  1759.               )
  1760.              ;; Try finding the transition in the DEFAULT component of the
  1761.              ;; transition table, but avoid doing this for unknown elements,
  1762.              ;; always use the default-default for them.
  1763.              ((and (or (eq '*data tag-name)
  1764.                        (w3-known-element-p tag-name))
  1765.                    (setq w3-p-s-transition
  1766.                          (nth 3 w3-p-s-state-transitions)))
  1767.               ;; body of cond clause empty
  1768.               )
  1769.              (t
  1770.               ;; Supply a default-default transition.
  1771.               (if (not (or (eq '*data tag-name)
  1772.                            (w3-known-element-p tag-name)))
  1773.                   (setq w3-p-s-transition
  1774.                         '(*discard *same "unknown element"))
  1775.  
  1776.                 ;; Decide whether to *close or *discard
  1777.                 ;; based on whether this element would be
  1778.                 ;; accepted as valid in an open ancestor.
  1779.                 (let ((open-list w3-p-d-open-element-stack)
  1780.                       (all-end-tags-omissible
  1781.                        (w3-element-end-tag-omissible w3-p-d-current-element))
  1782.                       state-transitions tran-list)
  1783.                   (if (catch 'found
  1784.                         (while open-list
  1785.                           (setq state-transitions
  1786.                                 (aref (w3-element-content-model
  1787.                                        (car open-list))
  1788.                                       (w3-element-state (car open-list))))
  1789.                           (if (memq tag-name (car state-transitions))
  1790.                               (throw 'found t))
  1791.                           (setq tran-list (nth 2 state-transitions))
  1792.                           (while tran-list
  1793.                             (cond ((memq tag-name (car (car tran-list)))
  1794.                                    (if (not (nth 3 (car tran-list)))
  1795.                                        ;; Not an error transition.
  1796.                                        (throw 'found t))
  1797.                                    (setq tran-list nil))
  1798.                                   (t
  1799.                                    (setq tran-list (cdr tran-list)))))
  1800.                           ;; The input item is not accepted in this
  1801.                           ;; ancestor.  Try again in next ancestor.
  1802.                           (or (w3-element-end-tag-omissible (car open-list))
  1803.                               (setq all-end-tags-omissible nil))
  1804.                           (setq open-list (cdr open-list)))
  1805.                         nil)
  1806.                       (setq w3-p-s-transition
  1807.                             (if (w3-element-end-tag-omissible
  1808.                                  w3-p-d-current-element)
  1809.                                 (if all-end-tags-omissible
  1810.                                     ;; Probably indicates a need to debug
  1811.                                     ;; the DTD state-transition tables.
  1812.                                     '(*close *same
  1813.                                              "missing transition in DTD?")
  1814.                                   ;; Error will be reported later.
  1815.                                   '(*close *same))
  1816.                               '(*close *same "not allowed here")))
  1817.                     (setq w3-p-s-transition
  1818.                           '(*discard *same "not allowed here")))))))
  1819.             
  1820.             ;; We have found a transition to take.  The transition is of
  1821.             ;; the format (ACTION NEW-STATE ERRORP) where the latter two
  1822.             ;; items are optional.
  1823.             
  1824.             ;; First, handle any state-change.
  1825.             (or (memq (car-safe (cdr w3-p-s-transition)) '(nil *same))
  1826.                 (w3-set-element-state
  1827.                  w3-p-d-current-element 
  1828.                  (if (eq '*next (car-safe (cdr w3-p-s-transition)))
  1829.                      (1+ (w3-element-state w3-p-d-current-element))
  1830.                    (car-safe (cdr w3-p-s-transition)))))
  1831.           
  1832.             ;; Handle any error message.
  1833.             (if (car-safe (cdr-safe (cdr w3-p-s-transition)))
  1834.                 (w3-debug-html 
  1835.                   :mandatory-if (and (eq '*data tag-name)
  1836.                                      (eq '*discard (car w3-p-s-transition)))
  1837.                   (format "Bad %s [%s], %s"
  1838.                           (if (eq '*data tag-name)
  1839.                               "data characters"
  1840.                             (concat "start-tag "
  1841.                                     (w3-sgml-name-to-string tag-name)))
  1842.                           (if (stringp (car (cdr (cdr w3-p-s-transition))))
  1843.                               (car (cdr (cdr w3-p-s-transition)))
  1844.                             "not allowed here")
  1845.                           (let ((action (car w3-p-s-transition)))
  1846.                             (cond ((eq '*discard action)
  1847.                                    "discarding bad item")
  1848.                                   ((eq '*close action)
  1849.                                    (concat "inferring </"
  1850.                                            (w3-sgml-name-to-string
  1851.                                             (w3-element-name
  1852.                                              w3-p-d-current-element))
  1853.                                            ">"))
  1854.                                   ((eq '*include action)
  1855.                                    "including bad item anyway")
  1856.                                   ((eq '*retry action)
  1857.                                    "*retry ??? you shouldn't see this")
  1858.                                   (t
  1859.                                    (concat "inferring <"
  1860.                                            (w3-sgml-name-to-string action)
  1861.                                            ">")))))))
  1862.             
  1863.             ;; Handle the action.
  1864.             (cond
  1865.              ((eq '*include (car w3-p-s-transition))
  1866.               (setq w3-p-s-includep t)
  1867.               ;; Exit loop.
  1868.               nil)
  1869.              ((eq '*close (car w3-p-s-transition))
  1870.               ;; Perform end-tag inference.
  1871.               (w3-close-element)        ; don't pass parameter
  1872.               ;; Loop and try again in parent element's content-model.
  1873.               t)
  1874.              ((eq '*discard (car w3-p-s-transition))
  1875.               (setq w3-p-s-includep nil)
  1876.               ;; Exit loop.
  1877.               nil)
  1878.              ((eq '*retry (car w3-p-s-transition))
  1879.               ;; Loop and try again after state change.
  1880.               t)
  1881.              ((symbolp (car w3-p-s-transition))
  1882.               ;; We need to open another element to contain the text,
  1883.               ;; probably a <P> (look in the state table).
  1884.               (w3-open-element (car w3-p-s-transition) nil)
  1885.               ;; Now we loop and try again in the new element's
  1886.               ;; content-model.
  1887.               t)
  1888.              (t
  1889.               (error "impossible transition")))))))
  1890.     
  1891.       ;; Empty while loop body.
  1892.       )
  1893.   
  1894.     ;; Return value to user indicating whether to include or discard item:
  1895.     ;;   t   ==> include
  1896.     ;;   nil ==> discard
  1897.     w3-p-s-includep)
  1898.  
  1899.   )
  1900.  
  1901.  
  1902. ;;;
  1903. ;;; Main parser.
  1904. ;;;
  1905.  
  1906. (defvar w3-last-parse-tree nil
  1907.   "Used for debugging only.  Stores the most recently computed parse tree
  1908. \(a tree, not a parse tag stream\).")
  1909.  
  1910. (defvar w3-invalid-sgml-char-replacement
  1911.   '(
  1912.     ;; These characters are apparently from an M$ character set (cp1252)
  1913.     (130 . ",")              ; single low-9 quotation mark
  1914.     (131 . "_f")          ; latin small letter f with hook
  1915.     (132 . ",,")          ; double low-9 quotation mark
  1916.     (133 . "...")          ; horizontal ellipsis
  1917.     (134 . "(dagger)")          ; dagger
  1918.     (135 . "(double dagger)") ; double dagger
  1919.     (136 . "^")              ; modifier letter circumflex accent
  1920.     (137 . "%o")          ; per mille sign
  1921.     (138 . "S\\v")          ; latin capital letter S with caron
  1922.     (139 . "<")              ; single left-pointing angle quotation mark
  1923.     (140 . "OE")          ; latin capital ligature OE
  1924.     (145 . "`")              ; left single quotation mark
  1925.     (146 . "'")              ; right single quotation mark
  1926.     (147 . "``")          ; left double quotation mark
  1927.     (148 . "''")          ; right double quotation mark
  1928.     (149 . "o")              ; bullet
  1929.     (150 . "--")          ; en dash
  1930.     (151 . "---")          ; em dash
  1931.     (152 . "~")              ; small tilde
  1932.     (153 . "(TM)")          ; trade mark sign
  1933.     (154 . "s\\v")          ; latin small letter s with caron
  1934.     (155 . ">")              ; single right-pointing angle quotation mark
  1935.     (156 . "oe")          ; latin small ligature oe
  1936.     (157 . "Y\\..")          ; latin capital letter Y with diaeresis
  1937.     )
  1938.   "Replacement for invalid SGML characters")
  1939.  
  1940. (defun w3-display-parse-tree (&optional ptree)
  1941.   (interactive)
  1942.   (with-output-to-temp-buffer "W3 HTML Parse Tree"
  1943.     (set-buffer standard-output)
  1944.     (emacs-lisp-mode)
  1945.     (require 'pp)
  1946.     (pp (or ptree w3-last-parse-tree))))
  1947.  
  1948. (defalias 'w3-display-last-parse-tree 'w3-display-parse-tree)
  1949.  
  1950. ;; For compatibility with the old parser interface.
  1951. (defalias 'w3-preparse-buffer 'w3-parse-buffer)
  1952.  
  1953. ;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1954. ;; %                                                    %
  1955. ;; % This is the *ONLY* valid entry point in this file! %
  1956. ;; %       DO NOT call any of the other functions!      %
  1957. ;; %                                                    %
  1958. ;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1959. (defun w3-parse-buffer (&optional buff)
  1960.   "Parse contents of BUFF as HTML.
  1961. BUFF defaults to the value of url-working-buffer.
  1962. Destructively alters contents of BUFF.
  1963. Returns a data structure containing the parsed information."
  1964.   (if (not w3-setup-done) (w3-do-setup))
  1965.   (set-buffer (or buff url-working-buffer))
  1966.   (setq buff (current-buffer))
  1967.   (set-syntax-table w3-sgml-md-syntax-table)
  1968.   (buffer-disable-undo (current-buffer))
  1969.   (widen)                               ; sanity checking
  1970.   (goto-char (point-max))
  1971.   (insert "\n")
  1972.   (goto-char (point-min))
  1973.   (setq case-fold-search t)             ; allows smaller regexp patterns
  1974.   
  1975.   ;; This is for ethiopic text.  Unfortunately, old MULE and new MULE conflict
  1976.   ;; on what exactly to call this function.
  1977.   (cond
  1978.    ((fboundp 'sera-to-fidel-marker)
  1979.     (let ((sera-being-called-by-w3 t))
  1980.       (funcall 'sera-to-fidel-marker)))
  1981.    ((fboundp 'ethio-sera-to-fidel-marker)
  1982.     (let ((sera-being-called-by-w3 t))
  1983.       (funcall 'ethio-sera-to-fidel-marker)))
  1984.    (t nil))
  1985.   (goto-char (point-min))
  1986.   
  1987.   ;; *** Should premunge line boundaries.
  1988.   ;; ********************
  1989.   
  1990.   (let* (
  1991.          ;; Speed hack, see the variable doc string.
  1992.          (gc-cons-threshold (if (> w3-gc-cons-threshold-multiplier 0)
  1993.                                 (* w3-gc-cons-threshold-multiplier
  1994.                                    gc-cons-threshold)
  1995.                               gc-cons-threshold))
  1996.  
  1997.          ;; Used to determine if we made any progress since the last loop.
  1998.          (last-loop-start (point-min))
  1999.         
  2000.          ;; How many iterations of the main loop have occurred.  Used only
  2001.          ;; to send messages to the user periodically, since this function
  2002.          ;; can take some time.
  2003.          (loop-count 0)
  2004.  
  2005.          ;; Precomputing the loop-invariant parts of this for speed.
  2006.          (status-message-format
  2007.           (if url-show-status
  2008.               (format "Parsed %%3d%%%% of %d..." (- (point-max) (point-min)))))
  2009.          
  2010.          ;; Use a float value for 100 if possible, otherwise integer.
  2011.          ;; Determine which we can use outside of the loop for speed.
  2012.          (one-hundred (funcall (if (fboundp 'float) 'float 'identity) 100))
  2013.          
  2014.          ;; The buffer which contains the HTML we are parsing.  This
  2015.          ;; variable is used to avoid using the more expensive
  2016.          ;; save-excursion.
  2017.          (parse-buffer (current-buffer))
  2018.          
  2019.          ;; Points to start of region of text since the previous tag.
  2020.          (between-tags-start (point-min))
  2021.          
  2022.          ;; Points past end of region of text since the previous tag.  Only
  2023.          ;; non-nil when the region has been completely determined and is
  2024.          ;; ready to be processed.
  2025.          between-tags-end
  2026.          
  2027.          ;; See doc string.
  2028.          w3-p-d-tag-name
  2029.          
  2030.          ;; See doc string.
  2031.          w3-p-d-end-tag-p
  2032.          
  2033.          ;; Is the tag we are looking at a null-end-tag-enabling
  2034.          ;; start-tag?
  2035.          net-tag-p
  2036.          
  2037.          ;; Attributes of the tag we are looking at.  An alist whose items
  2038.          ;; are pairs of the form (SYMBOL . STRING).
  2039.          tag-attributes
  2040.          
  2041.          ;; Points past end of attribute value we are looking at.  Points
  2042.          ;; past the syntactic construct, not the value of the attribute,
  2043.          ;; which may be at (1- attribute-value-end).
  2044.          attribute-value-end
  2045.          
  2046.          ;; Points past end of tag we are looking at.
  2047.          tag-end
  2048.          
  2049.          ;; See doc string.
  2050.          (w3-p-d-current-element (w3-fresh-element-for-tag '*document))
  2051.          
  2052.          ;; See doc string.
  2053.          (w3-p-d-open-element-stack (list (w3-fresh-element-for-tag '*holder)))
  2054.          
  2055.          ;; ***not implemented yet***
  2056.          (marked-section-undo-stack nil)
  2057.          
  2058.          ;; See doc string.
  2059.          (w3-p-d-debug-url t)
  2060.          
  2061.          ;; Any of the following variables with the comment ";*NESTED*"
  2062.          ;; are syntactic or semantic features that were introduced by
  2063.          ;; some containing element or marked section which will be undone
  2064.          ;; when we close that element or marked section.
  2065.          
  2066.          ;; See doc string.
  2067.          (w3-p-d-non-markup-chars nil) ;*NESTED*
  2068.          
  2069.          ;; See doc string.
  2070.          (w3-p-d-null-end-tag-enabled nil) ;*NESTED*
  2071.          
  2072.          ;; See doc string.
  2073.          (w3-p-d-in-parsed-marked-section nil) ;*NESTED*
  2074.          
  2075.          ;; See doc string.
  2076.          (w3-p-d-shortrefs nil)                ;*NESTED*
  2077.          
  2078.          ;; See doc string.
  2079.          (w3-p-d-shortref-chars nil)    ;*NESTED*
  2080.          
  2081.          ;; ******* maybe not needed.
  2082.          ;; 
  2083.          ;; ;; Are we recognizing start-tags?
  2084.          ;; (recognizing-start-tags t)     ;*NESTED*
  2085.          ;; 
  2086.          ;; ;; Are we recognizing end-tags?  If this is non-nil and not t,
  2087.          ;; ;; then only the end tag of the current open element is
  2088.          ;; ;; recognized.
  2089.          ;; (recognizing-end-tags t)       ;*NESTED*
  2090.          
  2091.          ;; See doc string.
  2092.          (w3-p-d-exceptions nil)        ;*NESTED*
  2093.          
  2094.          ;; Scratch variables used in this function
  2095.          ref attr-name attr-value content-model content open-list
  2096.          )
  2097.     ;; Scratch variables used by macros and defsubsts we call.
  2098.     (w3-p-s-let-bindings
  2099.       (w3-update-non-markup-chars)
  2100.       (setq w3-p-s-baseobject (url-generic-parse-url (url-view-url t)))
  2101.       ;; Main loop.  Handle markup as follows:
  2102.       ;;
  2103.       ;; non-empty tag: Handle the region since the previous tag as PCDATA,
  2104.       ;; RCDATA, CDATA, if allowed by syntax.  Then handle the tag.
  2105.       ;;
  2106.       ;; general entity (&name;): expand it and parse the result.
  2107.       ;;
  2108.       ;; shortref (_, {, }, and ^ in math stuff): Expand it and parse the
  2109.       ;; result.
  2110.       ;;
  2111.       ;; SGML marked section (<![ keywords [ conditional-text ]]>): Either
  2112.       ;; strip the delimiters and parse the result or delete.
  2113.       ;;
  2114.       ;; comment: Delete.
  2115.       ;;
  2116.       ;; empty tag (<>, </>): Handle as the appropriate tag.
  2117.       ;;
  2118.       ;; markup declaration (e.g. <!DOCTYPE ...>): Delete.
  2119.       ;;
  2120.       ;; SGML processing instruction (<?name>): Delete.
  2121.       ;;
  2122.       (while
  2123.           ;; Continue as long as we processed something last time and we
  2124.           ;; have more to process.
  2125.           (prog1 
  2126.               (not (and (= last-loop-start (point))
  2127.                         (eobp)))
  2128.             (setq last-loop-start (point)))
  2129.       
  2130.         ;; Display progress messages if asked and/or do incremental display
  2131.         ;; of results
  2132.         (cond ((= 0 (% (setq loop-count (1+ loop-count)) 40))
  2133.                (if status-message-format
  2134.                    (message status-message-format
  2135.                             ;; Percentage of buffer processed.
  2136.                             (/ (* (point) one-hundred) (point-max))))))
  2137.       
  2138.         ;; Go to next interesting thing in the buffer.
  2139.         (skip-chars-forward w3-p-d-non-markup-chars)
  2140.       
  2141.         ;; We are looking at a markup-starting character, and invalid
  2142.         ;; character, or end of buffer.
  2143.         (cond
  2144.  
  2145.          ((eq ?< (char-after (point)))
  2146.  
  2147.           ;; We are looking at a tag, comment, markup declaration, SGML marked
  2148.           ;; section, SGML processing instruction, or non-markup "<".
  2149.           (forward-char)
  2150.           (cond
  2151.  
  2152.            ((looking-at "/?\\([a-z][-a-z0-9.]*\\)")
  2153.             ;; We are looking at a non-empty tag.
  2154.  
  2155.             ;; Downcase it in the buffer, to save creation of a string
  2156.             (downcase-region (match-beginning 1) (match-end 1))
  2157.             (setq w3-p-d-tag-name
  2158.                   (intern (buffer-substring (match-beginning 1)
  2159.                                             (match-end 1))))
  2160.             (setq w3-p-d-end-tag-p (eq ?/ (char-after (point)))
  2161.                   between-tags-end (1- (point)))
  2162.             (goto-char (match-end 0))
  2163.           
  2164.             ;; Read the attributes from a start-tag.
  2165.             (if w3-p-d-end-tag-p
  2166.                 (if (looking-at "[ \t\r\n/]*[<>]")
  2167.                     nil
  2168.                   ;; This is in here to deal with those idiots who stick
  2169.                   ;; attribute/value pairs on end tags.  *sigh*
  2170.                   (w3-debug-html "Evil attributes on end tag.")
  2171.                   (skip-chars-forward "^>"))
  2172.            
  2173.              ;; Attribute values can be:
  2174.              ;;   "STRING"   where STRING does not contain the double quote
  2175.              ;;   'STRING'   where STRING does not contain the single quote
  2176.              ;;   name-start character, *name character
  2177.              ;;   *name character
  2178.              ;;   Digit, +name character
  2179.              ;;   +Digit
  2180.              ;; or a SPACE-separated list of one of the last four
  2181.              ;; possibilities (there is a comment somewhere that this is a
  2182.              ;; misinterpretation of the grammar, so we ignore this
  2183.              ;; possibility).
  2184.              (while
  2185.                  (looking-at
  2186.                   (eval-when-compile
  2187.                     (concat
  2188.                      ;; Leading whitespace.
  2189.                      "[ \n\r\t]*"
  2190.                      ;; The attribute name, possibly with a bad syntax
  2191.                      ;; component.
  2192.                      "\\([a-z_][-a-z0-9.]*\\(\\([_][-a-z0-9._]*\\)?\\)\\)"
  2193.                      ;; Trailing whitespace and perhaps an "=".
  2194.                      "[ \n\r\t]*\\(\\(=[ \n\r\t]*\\)?\\)")))
  2195.                
  2196.                (cond ((/= (match-beginning 2) (match-end 2))
  2197.                       (w3-debug-html
  2198.                         :nocontext
  2199.                         (format "Bad attribute name syntax: %s"
  2200.                                 (buffer-substring (match-beginning 1)
  2201.                                                   (match-end 1))))))
  2202.  
  2203.                ;; Downcase it in the buffer, to save creation of a string
  2204.                (downcase-region (match-beginning 1) (match-end 1))
  2205.                (setq attr-name
  2206.                      (intern (buffer-substring (match-beginning 1)
  2207.                                                (match-end 1))))
  2208.                (goto-char (match-end 0))
  2209.                (cond
  2210.                 ((< (match-beginning 4) (match-end 4))
  2211.                  ;; A value was specified (e.g. ATTRIBUTE=VALUE).
  2212.                  (cond
  2213.                   ((looking-at
  2214.                     (eval-when-compile
  2215.                       (concat
  2216.                        ;; Literal with double quotes.
  2217.                        "\"\\([^\"]*\\)\""
  2218.                        "\\|"
  2219.                        ;; Literal with single quotes.
  2220.                        "'\\([^']*\\)'"
  2221.                        "\\|"
  2222.                        ;; Handle bad HTML conflicting with NET-enabling
  2223.                        ;; start-tags.
  2224.                        "\\([-a-z0-9.]+/[-a-z0-9._/#]+\\)[ \t\n\r>]"
  2225.                        "\\|"
  2226.                        ;; SGML NAME-syntax attribute value.
  2227.                        "\\([-a-z0-9.]+\\)[ \t\n\r></]"
  2228.                        )))
  2229.                    (cond
  2230.                     ((or (match-beginning 1)
  2231.                          (match-beginning 2))
  2232.                      ;; We have an attribute value literal.
  2233.                      (narrow-to-region (1+ (match-beginning 0))
  2234.                                        (1- (match-end 0)))
  2235.                      
  2236.                      ;; In attribute value literals, EE and RS are ignored
  2237.                      ;; and RE and SEPCHAR characters sequences are
  2238.                      ;; replaced by SPACEs.
  2239.                      ;;
  2240.                      ;; (There is no way right now to get RS into one of
  2241.                      ;; these so that it can be ignored.  This is due to
  2242.                      ;; our using Unix line-handling conventions.)
  2243.                      (skip-chars-forward "^&\t\n\r")
  2244.                      (if (eobp)
  2245.                          nil
  2246.                        ;; We must expand entities and replace RS, RE,
  2247.                        ;; and SEPCHAR.
  2248.                        (goto-char (point-min))
  2249.                        (while (progn
  2250.                                 (skip-chars-forward "^&")
  2251.                                 (not (eobp)))
  2252.                          (w3-expand-entity-at-point-maybe))
  2253.                        (subst-char-in-region (point-min) (point-max) ?\t ? )
  2254.                        (subst-char-in-region (point-min) (point-max) ?\n ? ))
  2255.                      ;; Set this after we have changed the size of the
  2256.                      ;; attribute.
  2257.                      (setq attribute-value-end (1+ (point-max))))
  2258.                     ((match-beginning 4)
  2259.                      (setq attribute-value-end (match-end 4))
  2260.                      (narrow-to-region (point) attribute-value-end))
  2261.                     ((match-beginning 3)
  2262.                      (setq attribute-value-end (match-end 3))
  2263.                      (narrow-to-region (point) attribute-value-end)
  2264.                      ;; Horribly illegal non-SGML handling of bad
  2265.                      ;; HTML on the net.  This can break valid HTML.
  2266.                      (setq attr-value (buffer-substring (point)
  2267.                                                         (match-end 3)))
  2268.                      (w3-debug-html :nocontext
  2269.                        (format "Evil attribute value syntax: %s"
  2270.                                (buffer-substring (point-min) (point-max)))))
  2271.                     (t
  2272.                      (error "impossible attribute value"))))
  2273.                   ((memq (char-after (point)) '(?\" ?'))
  2274.                    ;; Missing terminating quote character.
  2275.                    (narrow-to-region (point)
  2276.                                      (progn
  2277.                                        (forward-char 1)
  2278.                                        (skip-chars-forward "^ \t\n\r'\"<>")
  2279.                                        (setq attribute-value-end (point))))
  2280.                    (w3-debug-html :nocontext
  2281.                      (format "Attribute value missing end quote: %s"
  2282.                              (buffer-substring (point-min) (point-max))))
  2283.                    (narrow-to-region (1+ (point-min)) (point-max)))
  2284.                   (t
  2285.                    ;; We have a syntactically invalid attribute value.  Let's
  2286.                    ;; make a best guess as to what the author intended.
  2287.                    (narrow-to-region (point)
  2288.                                      (progn
  2289.                                        (skip-chars-forward "^ \t\n\r'\"<>")
  2290.                                        (setq attribute-value-end (point))))
  2291.                    (w3-debug-html :nocontext
  2292.                      (format "Bad attribute value syntax: %s"
  2293.                              (buffer-substring (point-min) (point-max))))))
  2294.                  ;; Now we have isolated the attribute value.  We need to
  2295.                  ;; munge the value depending on the syntax of the
  2296.                  ;; attribute.
  2297.                  ;; *** Right now, we only implement the necessary munging
  2298.                  ;; for CDATA attributes, which is none.  I'm not sure why
  2299.                  ;; this happens to work for other attributes right now.
  2300.                  ;; For any other kind of attribute, we are supposed to
  2301.                  ;; * smash case
  2302.                  ;; * remove leading/trailing whitespace
  2303.                  ;; * smash multiple space sequences into single spaces
  2304.                  ;; * verify the syntax of each token
  2305.                  (setq attr-value (buffer-substring (point-min) (point-max)))
  2306.                  (case attr-name
  2307.                    (class
  2308.                     (setq attr-value (split-string attr-value "[ ,]+")))
  2309.                    (align
  2310.                     (if (string-match "^[ \t\r\n]*\\(.*\\)[ \t\r\n]*$"
  2311.                                       attr-value)
  2312.                         (setq attr-value (downcase
  2313.                                           (substring attr-value
  2314.                                                      (match-beginning 1)
  2315.                                                      (match-end 1))))
  2316.                       (setq attr-value (downcase attr-value)))
  2317.                     (setq attr-value (intern attr-value)))
  2318.                    ((src href)
  2319.                     ;; I should expand URLs here
  2320.                     )
  2321.                    (otherwise nil)
  2322.                    )
  2323.                  (widen)
  2324.                  (goto-char attribute-value-end))
  2325.                 (t
  2326.                  ;; No value was specified, in which case NAME should be
  2327.                  ;; taken as ATTRIBUTE=NAME where NAME is one of the
  2328.                  ;; enumerated values for ATTRIBUTE.
  2329.                  ;; We assume here that ATTRIBUTE is the same as NAME.
  2330.                  ;; *** Another piece of code will fix the attribute name if it
  2331.                  ;; is wrong.
  2332.                  (setq attr-value (symbol-name attr-name))))
  2333.              
  2334.                ;; Accumulate the attributes.
  2335.                (setq tag-attributes (cons (cons attr-name attr-value)
  2336.                                           tag-attributes)))
  2337.  
  2338.              (if (and (eq w3-p-d-tag-name 'img)
  2339.                       (not (assq 'alt tag-attributes)))
  2340.                  (w3-debug-html :bad-style
  2341.                                 :outer
  2342.                                 "IMG element has no ALT attribute"))
  2343.              (cond
  2344.               ((and (eq w3-p-d-tag-name 'base)
  2345.                     (setq w3-p-s-baseobject
  2346.                           (or (assq 'src tag-attributes)
  2347.                               (assq 'href tag-attributes))))
  2348.                (setq w3-p-s-baseobject (url-generic-parse-url
  2349.                                         (cdr w3-p-s-baseobject))))
  2350.               ((setq w3-p-s-btdt (or (assq 'src tag-attributes)
  2351.                                      (assq 'background tag-attributes)
  2352.                                      (assq 'href tag-attributes)
  2353.                                      (assq 'action tag-attributes)))
  2354.                (setcdr w3-p-s-btdt (url-expand-file-name (cdr w3-p-s-btdt)
  2355.                                                          w3-p-s-baseobject))
  2356.                (setq w3-p-s-btdt (if (url-have-visited-url (cdr w3-p-s-btdt))
  2357.                                      ":visited"
  2358.                                    ":link"))
  2359.                (if (assq 'class tag-attributes)
  2360.                    (setcdr (assq 'class tag-attributes)
  2361.                            (cons w3-p-s-btdt
  2362.                                  (cdr (assq 'class tag-attributes))))
  2363.                  (setq tag-attributes (cons (cons 'class (list w3-p-s-btdt))
  2364.                                             tag-attributes))))
  2365.               )
  2366.              (if (not (eq w3-p-d-tag-name 'input))
  2367.                  nil
  2368.                (setq w3-p-s-btdt (concat ":"
  2369.                                          (downcase
  2370.                                           (or (cdr-safe
  2371.                                                (assq 'type tag-attributes))
  2372.                                               "text"))))
  2373.                (if (assq 'class tag-attributes)
  2374.                    (setcdr (assq 'class tag-attributes)
  2375.                            (cons w3-p-s-btdt
  2376.                                  (cdr (assq 'class tag-attributes))))
  2377.                  (setq tag-attributes (cons (cons 'class (list w3-p-s-btdt))
  2378.                                             tag-attributes))))
  2379.              )
  2380.           
  2381.             ;; Process the end of the tag.
  2382.             (skip-chars-forward " \t\n\r")
  2383.             (cond ((eq ?> (char-after (point)))
  2384.                    ;; Ordinary tag end.
  2385.                    (forward-char 1))
  2386.                   ((and (eq ?/ (char-after (point)))
  2387.                         (not w3-p-d-end-tag-p))
  2388.                    ;; This is a NET-enabling start-tag.
  2389.                    (setq net-tag-p t)
  2390.                    (forward-char 1))
  2391.                   ((eq ?< (char-after (point)))
  2392.                    ;; *** Strictly speaking, the following text has to
  2393.                    ;; lexically be STAGO or ETAGO, which means that it
  2394.                    ;; can't match some other lexical unit.
  2395.                    ;; Unclosed tag.
  2396.                    nil)
  2397.                   (t
  2398.                    ;; Syntax error.
  2399.                    (w3-debug-html
  2400.                      (format "Bad unclosed %s%s tag"
  2401.                              (if w3-p-d-end-tag-p "/" "")
  2402.                              (w3-sgml-name-to-string w3-p-d-tag-name)))))
  2403.             
  2404.             (setq tag-end (point)))
  2405.            
  2406.            ((looking-at "/?>")
  2407.             ;; We are looking at an empty tag (<>, </>).
  2408.             (setq w3-p-d-end-tag-p (eq ?/ (char-after (point))))
  2409.             (setq w3-p-d-tag-name (if w3-p-d-end-tag-p
  2410.                                (w3-element-name w3-p-d-current-element)
  2411.                              ;; *** Strictly speaking, if OMITTAG NO, then
  2412.                              ;; we should use the most recently closed tag.
  2413.                              ;; But OMITTAG YES in HTML and I'm lazy.
  2414.                              (w3-element-name w3-p-d-current-element)))
  2415.             (setq tag-attributes nil)
  2416.             ;; *** Make sure this is not at top level.
  2417.             (setq between-tags-end (1- (point)))
  2418.             (setq tag-end (match-end 0)))
  2419.          
  2420.            ;; *** In SGML, <(doctype)element> is valid tag syntax.  This
  2421.            ;; cannot occur in HTML because the CONCUR option is off in the
  2422.            ;; SGML declaration.
  2423.          
  2424.            ((looking-at "!--")
  2425.             ;; We found a comment, delete to end of comment.
  2426.             (delete-region
  2427.              (1- (point))
  2428.              (progn
  2429.                (forward-char 1)
  2430.                ;; Skip over pairs of -- ... --.
  2431.                ;;
  2432.                ;; This can cause us to hit a stack overflow in the regexp
  2433.                ;; engine.  And I'm not sure its correct anyway.  Lets just
  2434.                ;; always fall back to the (semi) non-SGML way of dealing
  2435.                ;; with comments.  WMP  12/24/97
  2436. ;;;               (if (looking-at "\\(--[^-]*\\(-[^-]+\\)*--[ \t\r\n]*\\)+>")
  2437. ;;;                   (goto-char (match-end 0))
  2438. ;;;                 ;; Syntax error!
  2439. ;;;                 (w3-debug-html
  2440. ;;;                   "Bad comment (unterminated or unbalanced \"--\" pairs)")
  2441. ;;;                 (forward-char 2)
  2442. ;;;                 (or (re-search-forward "--[ \t\r\n]*>" nil t)
  2443. ;;;                     (search-forward ">" nil t)))
  2444.                (forward-char 2)
  2445.                (or (re-search-forward "--[ \t\r\n]*>" nil t)
  2446.                    (search-forward ">" nil t))
  2447.                (point))))
  2448.            
  2449.            ((looking-at "!>\\|\\?[^>]*>")
  2450.             ;; We are looking at an empty comment or a processing
  2451.             ;; instruction.  Delete it.
  2452.             (replace-match "")
  2453.             (delete-char -1))
  2454.  
  2455.            ((looking-at "![a-z]")
  2456.             ;; We are looking at a markup declaration.  Delete it.
  2457.             ;; *** Technically speaking, to handle valid HTML I think we
  2458.             ;; need to handle "<!USEMAP ... >" declarations.  In the future,
  2459.             ;; to handle general SGML, we should parse "<!DOCTYPE ... >"
  2460.             ;; declarations as well (which can contain other declarations).
  2461.             ;; In the very distant future, perhaps we will handle "<!SGML
  2462.             ;; ... >" declarations.
  2463.             ;; *** Should warn if it's not SGML, DOCTYPE, or USEMAP.
  2464.             (backward-char 1)
  2465.             (delete-region
  2466.              (point)
  2467.              (progn
  2468.                (condition-case nil
  2469.                    (forward-sexp 1)
  2470.                  (error
  2471.                   ;; *** This might not actually be bad syntax, but might
  2472.                   ;; instead be a -- ... -- comment with unbalanced
  2473.                   ;; parentheses somewhere inside the declaration.  Handling
  2474.                   ;; this properly would require full parsing of markup
  2475.                   ;; declarations, a goal for the future.
  2476.                   (w3-debug-html "Bad <! syntax.")
  2477.                   (skip-chars-forward "^>")
  2478.                   (if (eq ?> (char-after (point)))
  2479.                       (forward-char))))
  2480.                (point))))
  2481.          
  2482.            ((looking-at "!\\\[\\(\\([ \t\n\r]*[a-z]+\\)+[ \t\n\r]*\\)\\\[")
  2483.             ;; We are looking at a marked section.
  2484.             ;; *** Strictly speaking, we should issue a warning if the
  2485.             ;; keywords are invalid or missing or if the "[" does not follow.
  2486.             ;; We must look at the keywords to understand how to parse it.
  2487.             ;; *** Strictly speaking, we should perform parameter entity
  2488.             ;; substitution on the keywords first.
  2489.             (goto-char (match-beginning 1))
  2490.             (insert ?\))
  2491.             (goto-char (1- (match-beginning 0)))
  2492.             (delete-char 3)
  2493.             (insert ?\()
  2494.             (backward-char 1)
  2495.             (let* ((keywords (read (current-buffer)))
  2496.                    ;; Multiple keywords may appear, but only the most
  2497.                    ;; significant takes effect.  Rank order is IGNORE, CDATA,
  2498.                    ;; RCDATA, INCLUDE, and TEMP.  INCLUDE and TEMP have the
  2499.                    ;; same effect.
  2500.                    (keyword (car-safe (cond ((memq 'IGNORE keywords))
  2501.                                             ((memq 'CDATA keywords))
  2502.                                             ((memq 'RCDATA keywords))
  2503.                                             ((memq 'INCLUDE keywords))
  2504.                                             ((memq 'TEMP keywords))))))
  2505.               (or (eq ?\[ (char-after (point)))
  2506.                   ;; I probably shouldn't even check this, since it is so
  2507.                   ;; impossible.
  2508.                   (error "impossible ??"))
  2509.               (forward-char 1)
  2510.               (delete-region (1- (match-beginning 0)) (point))
  2511.               (cond ((eq 'IGNORE keyword)
  2512.                      ;; Scan forward skipping over matching <![ ... ]]>
  2513.                      ;; until we find an unmatched "]]>".
  2514.                      (let ((ignore-nesting 1)
  2515.                            (start-pos (point)))
  2516.                        (while (> ignore-nesting 0)
  2517.                          (if (re-search-forward "<!\\\\\[\\|\]\]>" nil t)
  2518.                              (setq ignore-nesting
  2519.                                    (if (eq ?> (preceding-char))
  2520.                                        (1- ignore-nesting)
  2521.                                      (1+ ignore-nesting)))
  2522.                            (w3-debug-html
  2523.                              "Unterminated IGNORE marked section.")
  2524.                            (setq ignore-nesting 0)
  2525.                            (goto-char start-pos)))
  2526.                        (delete-region start-pos (point))))
  2527.                     ((eq 'CDATA keyword)
  2528.                      (error "***unimplemented***"))
  2529.                     ((eq 'RCDATA keyword)
  2530.                      (error "***unimplemented***"))
  2531.                     ((memq keyword '(INCLUDE TEMP))
  2532.                      (error "***unimplemented***")))))
  2533.            ((and (looking-at "!")
  2534.                  w3-netscape-compatible-comments)
  2535.             ;; Horribly illegal non-SGML handling of bad HTML on the net.
  2536.             ;; This can break valid HTML.
  2537.             ;; This arises because Netscape discards anything looking like
  2538.             ;; "<!...>".  So people expect they can use this construct as
  2539.             ;; a comment.
  2540.             (w3-debug-html "Evil <! comment syntax.")
  2541.             (backward-char 1)
  2542.             (delete-region
  2543.              (point)
  2544.              (progn
  2545.                (skip-chars-forward "^>")
  2546.                (if (eq ?> (char-after (point)))
  2547.                    (forward-char))
  2548.                (point))))
  2549.            (t
  2550.             ;; This < is not a markup character.  Pretend we didn't notice
  2551.             ;; it at all.  We have skipped over the < already, so just loop
  2552.             ;; again.
  2553.             )))
  2554.        
  2555.          ((eq ?& (char-after (point)))
  2556.           (w3-expand-entity-at-point-maybe))
  2557.  
  2558.          ((and (eq ?\] (char-after (point)))
  2559.                w3-p-d-in-parsed-marked-section
  2560.                (looking-at "]]>"))
  2561.           ;; *** handle the end of a parsed marked section.
  2562.           (error "***unimplemented***"))
  2563.  
  2564.          ((and (eq ?/ (char-after (point)))
  2565.                w3-p-d-null-end-tag-enabled)
  2566.           ;; We are looking at a null end tag.
  2567.           (setq w3-p-d-end-tag-p t)
  2568.           (setq between-tags-end (point))
  2569.           (setq tag-end (1+ (point)))
  2570.           (setq w3-p-d-tag-name (w3-element-name w3-p-d-current-element)))
  2571.        
  2572.          ;; This can be slow, since we'll hardly ever get here.
  2573.          ;; *** Strictly speaking, I think we're supposed to handle
  2574.          ;; shortrefs that begin with the same characters as other markup,
  2575.          ;; preferring the longest match.
  2576.          ;; I will assume that shortrefs never begin with <, &, \], /.
  2577.          ((setq ref (catch 'found-shortref
  2578.                       (let ((refs w3-p-d-shortrefs))
  2579.                         (while refs
  2580.                           (if (looking-at (car (car refs)))
  2581.                               (throw 'found-shortref (cdr (car refs))))
  2582.                           (setq refs (cdr refs))))))
  2583.           ;; We are looking at a shortref for which there is an
  2584.           ;; expansion defined in the current syntax.  Replace with the
  2585.           ;; expansion, leaving point at the beginning so it will be parsed
  2586.           ;; on the next loop.
  2587.           ;; *** eek.  This is wrong if the shortref is for an entity with
  2588.           ;; CDATA syntax which should not be reparsed for tags.
  2589.           (replace-match "")
  2590.           (let ((pt (point)))
  2591.             (insert ref)
  2592.             (goto-char pt)))
  2593.          
  2594.          ((looking-at (eval-when-compile
  2595.                         (concat "[" (w3-invalid-sgml-chars) "]")))
  2596.           (w3-debug-html
  2597.             (format "Invalid SGML character: %c" (char-after (point))))
  2598.           (insert (or (cdr-safe (assq (char-after (point))
  2599.                                       w3-invalid-sgml-char-replacement)) ""))
  2600.           (delete-char 1))
  2601.          ((eobp)
  2602.           ;; We have finished the buffer.  Make sure we process the last
  2603.           ;; piece of text, if any.
  2604.           (setq between-tags-end (point))
  2605.           ;; We have to test what's on the element stack because this
  2606.           ;; piece of code gets executed twice.
  2607.           (cond ((not (eq '*holder (w3-element-name w3-p-d-current-element)))
  2608.                  ;; This forces the calculation of implied omitted end tags.
  2609.                  (setq w3-p-d-tag-name '*document)
  2610.                  (setq w3-p-d-end-tag-p t)
  2611.                  (setq tag-end (point)))))
  2612.          
  2613.          (t
  2614.           (error "unreachable code, this can't happen")))
  2615.         
  2616.         ;; If we have determined the boundaries of a non-empty between-tags
  2617.         ;; region of text, then handle it.
  2618.         (cond
  2619.          (between-tags-end
  2620.           (cond
  2621.            ((< between-tags-start between-tags-end)
  2622.             ;; We have a non-empty between-tags region.
  2623.  
  2624.             ;; We check if it's entirely whitespace, because we record the
  2625.             ;; transitions for whitespace separately from those for
  2626.             ;; data with non-whitespace characters.
  2627.             (goto-char between-tags-start)
  2628.             (skip-chars-forward " \t\n\r" between-tags-end)
  2629.             (cond
  2630.              ((w3-grok-tag-or-data (prog1 
  2631.                                        (if (= between-tags-end (point))
  2632.                                            '*space
  2633.                                          '*data)
  2634.                                      (goto-char between-tags-end)))
  2635.               ;; We have to include the text in the current element's
  2636.               ;; contents.  If this is the first item in the current
  2637.               ;; element's contents, don't include a leading newline if
  2638.               ;; there is one.  Add a trailing newline as a separate text
  2639.               ;; item so that it can be removed later if it turns out to
  2640.               ;; be the last item in the current element's contents when
  2641.               ;; the current element is closed.
  2642.               ;; *** We could perform this test before calling
  2643.               ;; w3-grok-tag-or-data, but it's not clear which will be
  2644.               ;; faster in practice.
  2645.               (or (setq content (w3-element-content w3-p-d-current-element))
  2646.                   ;; *** Strictly speaking, in SGML the record end is
  2647.                   ;; carriage return, not line feed.
  2648.                   (if (eq ?\n (char-after between-tags-start))
  2649.                       (setq between-tags-start (1+ between-tags-start))))
  2650.               (if (= between-tags-start (point))
  2651.                   ;; Do nothing.
  2652.                   nil
  2653.                 ;; We are definitely going to add data characters to the
  2654.                 ;; content.
  2655.                 (cond
  2656.                  ((and (= ?\n (preceding-char))
  2657.                        (/= between-tags-start (1- (point))))
  2658.                   (setq content (cons (buffer-substring between-tags-start
  2659.                                                         (1- (point)))
  2660.                                       content))
  2661.                   (setq content (cons "\n" content)))
  2662.                  (t
  2663.                   (setq content (cons (buffer-substring between-tags-start
  2664.                                                         (point))
  2665.                                       content))))
  2666.                 (w3-set-element-content w3-p-d-current-element content))))))
  2667.           
  2668.           (setq between-tags-end nil)))
  2669.       
  2670.         ;; If the previous expression modified (point), then it went to
  2671.         ;; the value of between-tags-end.
  2672.       
  2673.         ;; If we found a start or end-tag, we need to handle it.
  2674.         (cond
  2675.          (w3-p-d-tag-name
  2676.         
  2677.           ;; Move past the tag and prepare for next between-tags region.
  2678.           (goto-char tag-end)
  2679.           (setq between-tags-start (point))
  2680.         
  2681.           (cond
  2682.            (w3-p-d-end-tag-p
  2683.             ;; Handle an end-tag.
  2684.             (if (eq w3-p-d-tag-name (w3-element-name w3-p-d-current-element))
  2685.                 (w3-close-element)
  2686.               ;; Handle the complex version.  We have to search up (down?)
  2687.               ;; the open element stack to find the element that matches (if
  2688.               ;; any).  Then we close all of the elements.  On a conforming
  2689.               ;; SGML document this can do no wrong and it's not
  2690.               ;; unreasonable on a non-conforming document.
  2691.             
  2692.               ;; Can't safely modify stack until we know the element we want
  2693.               ;; to find is in there, so work with a copy.
  2694.               (setq open-list w3-p-d-open-element-stack)
  2695.               (while (and open-list
  2696.                           (not (eq w3-p-d-tag-name
  2697.                                    (w3-element-name (car open-list)))))
  2698.                 (setq open-list (cdr open-list)))
  2699.               (cond (open-list
  2700.                      ;; We found a match.  Pop elements.
  2701.                      ;; We will use the following value as a sentinel.
  2702.                      (setq open-list (cdr open-list))
  2703.                      (while (not (eq open-list w3-p-d-open-element-stack))
  2704.                        (w3-close-element t))
  2705.                      (w3-close-element))
  2706.                     (t
  2707.                      ;; Bogus end tag.
  2708.                      (w3-debug-html
  2709.                        (format "Unmatched end-tag </%s>"
  2710.                                (w3-sgml-name-to-string w3-p-d-tag-name)))))))
  2711.            (t
  2712.             ;; Handle a start-tag.
  2713.             (cond
  2714.              ;; Check if the new element is allowed in the current element's
  2715.              ;; content model.
  2716.              ((w3-grok-tag-or-data w3-p-d-tag-name)
  2717.               (w3-open-element w3-p-d-tag-name tag-attributes)
  2718.             
  2719.               ;; Handle NET-enabling start tags.
  2720.               (cond ((and net-tag-p
  2721.                           (not w3-p-d-null-end-tag-enabled))
  2722.                      ;; Save old values.
  2723.                      (w3-set-element-undo-list 
  2724.                       w3-p-d-current-element 
  2725.                       (cons (cons 'w3-p-d-non-markup-chars
  2726.                                   w3-p-d-non-markup-chars)
  2727.                             (cons '(w3-p-d-null-end-tag-enabled . nil)
  2728.                                   (w3-element-undo-list w3-p-d-current-element))))
  2729.                      ;; Alter syntax.
  2730.                      (setq w3-p-d-null-end-tag-enabled t)
  2731.                      (w3-update-non-markup-chars)))
  2732.             
  2733.               (setq content-model
  2734.                     (w3-element-content-model w3-p-d-current-element))
  2735.             
  2736.               ;; If the element does not have parsed contents, then we
  2737.               ;; can find its contents immediately.
  2738.               (cond
  2739.                ((memq content-model '(EMPTY CDATA XCDATA XXCDATA RCDATA))
  2740.                 (cond
  2741.                  ((eq 'EMPTY content-model)
  2742.                   (w3-close-element))
  2743.                  ((eq 'CDATA content-model)
  2744.                   ;; CDATA: all data characters until an end-tag.  We'll
  2745.                   ;; process the end-tag on the next loop.
  2746.                   (if (re-search-forward (if w3-p-d-null-end-tag-enabled
  2747.                                              "</[a-z>]\\|/"
  2748.                                            "</[a-z>]")
  2749.                                          nil 'move)
  2750.                       (goto-char (match-beginning 0))))
  2751.                  ((eq 'XCDATA content-model)
  2752.                   ;; XCDATA: special non-SGML-standard mode which includes
  2753.                   ;; all data characters until "</foo" is seen where "foo"
  2754.                   ;; is the name of this element (for XMP and LISTING).
  2755.                   (if (search-forward 
  2756.                        (concat "</" (symbol-name
  2757.                                      (w3-element-name w3-p-d-current-element)))
  2758.                        nil 'move)
  2759.                       (goto-char (match-beginning 0))))
  2760.                  ((eq 'XXCDATA content-model)
  2761.                   ;; XXCDATA: special non-SGML-standard mode which includes
  2762.                   ;; all data until end-of-entity (end-of-buffer for us)
  2763.                   ;; (for PLAINTEXT).
  2764.                   (goto-char (point-max)))
  2765.                  ((eq 'RCDATA content-model)
  2766.                   ;; RCDATA: all data characters until end-tag is seen,
  2767.                   ;; except that entities are expanded first, although the
  2768.                   ;; expansions are _not_ scanned for end-tags, although the
  2769.                   ;; expansions _are_ scanned for further entity
  2770.                   ;; references.
  2771.                   (while (progn
  2772.                            (if (re-search-forward (if w3-p-d-null-end-tag-enabled
  2773.                                                       "</[a-z>]\\|[/&]"
  2774.                                                     "</[a-z>]\\|&")
  2775.                                                   nil 'move)
  2776.                                (goto-char (match-beginning 0)))
  2777.                            (eq ?& (char-after (point))))
  2778.                     (w3-expand-entity-at-point-maybe)))))))
  2779.              (t
  2780.               ;; The element is illegal here.  We'll just discard the start
  2781.               ;; tag as though we never saw it.
  2782.               ))))
  2783.         
  2784.           (setq w3-p-d-tag-name nil)
  2785.           (setq w3-p-d-end-tag-p nil)
  2786.           (setq net-tag-p nil)
  2787.           (setq tag-attributes nil)
  2788.           (setq tag-end nil)))
  2789.         
  2790.         ;; End of main while loop.
  2791.         )
  2792.     
  2793.       ;; We have finished parsing the buffer!
  2794.       (if status-message-format
  2795.           (message "%sdone" (format status-message-format 100)))
  2796.     
  2797.       ;; *** For debugging, save the true parse tree.
  2798.       ;; *** Make this look inside *DOCUMENT.
  2799.       (setq w3-last-parse-tree
  2800.             (w3-element-content w3-p-d-current-element))
  2801.  
  2802.       (w3-element-content w3-p-d-current-element)
  2803.       )))
  2804.  
  2805.  
  2806.  
  2807. (provide 'w3-parse)
  2808.  
  2809. ;; Local variables:
  2810. ;; indent-tabs-mode: nil
  2811. ;; end:
  2812.